Merge "Camera2: Add distortion correction support" into pi-dev
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index a40cd11..5fd4886 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -1313,8 +1313,8 @@
* Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is START | PRECAPTURE | Start AE precapture metering sequence
* Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL| INACTIVE | Currently active precapture metering sequence is canceled</p>
* <p>If the camera device supports AE external flash mode (ON_EXTERNAL_FLASH is included in
- * ACAMERA_CONTROL_AE_AVAILABLE_MODES), aeState must be FLASH_REQUIRED after the camera device
- * finishes AE scan and it's too dark without flash.</p>
+ * ACAMERA_CONTROL_AE_AVAILABLE_MODES), ACAMERA_CONTROL_AE_STATE must be FLASH_REQUIRED after
+ * the camera device finishes AE scan and it's too dark without flash.</p>
* <p>For the above table, the camera device may skip reporting any state changes that happen
* without application intervention (i.e. mode switch, trigger, locking). Any state that
* can be skipped in that manner is called a transient state.</p>
@@ -1335,6 +1335,7 @@
* @see ACAMERA_CONTROL_AE_LOCK
* @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
+ * @see ACAMERA_CONTROL_AE_STATE
* @see ACAMERA_CONTROL_MODE
* @see ACAMERA_CONTROL_SCENE_MODE
*/
@@ -5565,9 +5566,11 @@
* for the external flash. Otherwise, this mode acts like ON.</p>
* <p>When the external flash is turned off, AE mode should be changed to one of the
* other available AE modes.</p>
- * <p>If the camera device supports AE external flash mode, aeState must be
- * FLASH_REQUIRED after the camera device finishes AE scan and it's too dark without
+ * <p>If the camera device supports AE external flash mode, ACAMERA_CONTROL_AE_STATE must
+ * be FLASH_REQUIRED after the camera device finishes AE scan and it's too dark without
* flash.</p>
+ *
+ * @see ACAMERA_CONTROL_AE_STATE
*/
ACAMERA_CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5,
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 66e4400..4991e50 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -54,17 +54,18 @@
proto: {
export_proto_headers: true,
- type: "lite",
+ type: "lite",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-lite",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
@@ -86,24 +87,25 @@
proto: {
export_proto_headers: true,
- type: "full",
+ type: "full",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-full",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
// Suppress unused parameter and no error options. These cause problems
- // when using the map type in a proto definition.
- "-Wno-unused-parameter",
- "-Wno-error",
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
],
}
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 5d97188..4e8ad52 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -32,6 +32,7 @@
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
#include <mediadrm/DrmHal.h>
@@ -63,9 +64,27 @@
// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
// in the MediaDrm API.
constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+template<typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ if (size == 0) {
+ return "";
+ }
+ CHECK(sizeof(data[0] == 1));
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
}
+} // anonymous namespace
+
namespace android {
#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
@@ -101,15 +120,6 @@
return hidl_string(string.string());
}
-std::string toHexString(const std::string& str) {
- std::ostringstream out;
- out << std::hex << std::setfill('0');
- for (size_t i = 0; i < str.size(); i++) {
- out << std::setw(2) << (int)(str[i]);
- }
- return out.str();
-}
-
static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
switch(level) {
case SecurityLevel::SW_SECURE_CRYPTO:
@@ -340,6 +350,7 @@
sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName) {
+ mAppPackageName = appPackageName;
mMetrics.SetAppPackageName(appPackageName);
sp<IDrmPlugin> plugin;
@@ -1353,9 +1364,10 @@
if (result != OK) {
ALOGE("Failed to serialize framework metrics: %d", result);
}
- serializedMetrics = toHexString(serializedMetrics);
- if (!serializedMetrics.empty()) {
- item.setCString("serialized_metrics", serializedMetrics.c_str());
+ std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
+ serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
}
if (!item.selfrecord()) {
ALOGE("Failed to self record framework metrics");
@@ -1364,14 +1376,16 @@
void DrmHal::reportPluginMetrics() const
{
- Vector<uint8_t> metrics;
+ Vector<uint8_t> metricsVector;
String8 vendor;
String8 description;
if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
- status_t res = android::reportDrmPluginMetrics(
- metrics, vendor, description);
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ std::string metricsString = toBase64StringNoPad(metricsVector.array(),
+ metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
+ description, mAppPackageName);
if (res != OK) {
ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 6c97f2b..5cb48bf 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -16,80 +16,35 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "PluginMetricsReporting"
-#include <utils/Log.h>
-#include <inttypes.h>
#include <media/PluginMetricsReporting.h>
-#include <media/MediaAnalyticsItem.h>
+#include <inttypes.h>
-#include "protos/metrics.pb.h"
+#include <media/MediaAnalyticsItem.h>
+#include <utils/Log.h>
+
namespace android {
namespace {
-using android::drm_metrics::MetricsGroup;
-using android::drm_metrics::MetricsGroup_Metric;
-using android::drm_metrics::MetricsGroup_Metric_MetricValue;
+constexpr char kSerializedMetricsField[] = "serialized_metrics";
-const char* const kParentAttribute = "/parent/external";
-
-status_t reportMetricsGroup(const MetricsGroup& metricsGroup,
- const String8& batchName,
- const int64_t* parentId) {
- MediaAnalyticsItem analyticsItem(batchName.c_str());
+status_t reportVendorMetrics(const std::string& metrics,
+ const String8& name,
+ const String8& appPackageName) {
+ MediaAnalyticsItem analyticsItem(name.c_str());
analyticsItem.generateSessionID();
- int64_t sessionId = analyticsItem.getSessionID();
- if (parentId != NULL) {
- analyticsItem.setInt64(kParentAttribute, *parentId);
- }
- // Report the package name.
- if (metricsGroup.has_app_package_name()) {
- std::string app_package_name(metricsGroup.app_package_name().c_str(),
- metricsGroup.app_package_name().size());
- analyticsItem.setPkgName(app_package_name);
- }
-
- for (int i = 0; i < metricsGroup.metric_size(); ++i) {
- const MetricsGroup_Metric& metric = metricsGroup.metric(i);
- if (!metric.has_name()) {
- ALOGE("Metric with no name.");
- return BAD_VALUE;
- }
-
- if (!metric.has_value()) {
- ALOGE("Metric with no value.");
- return BAD_VALUE;
- }
-
- const MetricsGroup_Metric_MetricValue& value = metric.value();
- if (value.has_int_value()) {
- analyticsItem.setInt64(metric.name().c_str(),
- value.int_value());
- } else if (value.has_double_value()) {
- analyticsItem.setDouble(metric.name().c_str(),
- value.double_value());
- } else if (value.has_string_value()) {
- analyticsItem.setCString(metric.name().c_str(),
- value.string_value().c_str());
- } else {
- ALOGE("Metric Value with no actual value.");
- return BAD_VALUE;
- }
+ std::string app_package_name(appPackageName.c_str(), appPackageName.size());
+ analyticsItem.setPkgName(app_package_name);
+ if (metrics.size() > 0) {
+ analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
}
if (!analyticsItem.selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, sessionId);
- }
-
- for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
- const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
- status_t res = reportMetricsGroup(subGroup, batchName, &sessionId);
- if (res != OK) {
- return res;
- }
+ ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
}
return OK;
@@ -111,21 +66,16 @@
} // namespace
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendor,
- const String8& description) {
- MetricsGroup root_metrics_group;
- if (!root_metrics_group.ParseFromArray(serializedMetrics.array(),
- serializedMetrics.size())) {
- ALOGE("Failure to parse.");
- return BAD_VALUE;
- }
+ const String8& description,
+ const String8& appPackageName) {
String8 name = String8::format("drm.vendor.%s.%s",
sanitize(vendor).c_str(),
sanitize(description).c_str());
- return reportMetricsGroup(root_metrics_group, name, NULL);
+ return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
}
} // namespace android
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
index aa26f5f..6160e6f 100644
--- a/drm/libmediadrm/protos/metrics.proto
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -18,33 +18,6 @@
package android.drm_metrics;
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
- message Metric {
- message MetricValue {
- // Exactly one of the following values must be set.
- optional int64 int_value = 1;
- optional double double_value = 2;
- optional string string_value = 3;
- }
-
- // The name of the metric. Must be valid UTF-8. Required.
- optional string name = 1;
-
- // The value of the metric. Required.
- optional MetricValue value = 2;
- }
-
- // The list of name/value pairs of metrics.
- repeated Metric metric = 1;
-
- // Allow multiple sub groups of metrics.
- repeated MetricsGroup metric_sub_group = 2;
-
- // Name of the application package associated with the metrics.
- optional string app_package_name = 3;
-}
// This message contains the specific metrics captured by DrmMetrics. It is
// used for serializing and logging metrics.
@@ -72,7 +45,7 @@
// The Counter message is used to store a count value with an associated
// Attribute.
message Counter {
- optional int64 count = 1;
+ optional uint64 count = 1;
// Represents the attributes associated with this counter instance.
optional Attributes attributes = 2;
}
@@ -80,11 +53,11 @@
// The DistributionMetric is meant to capture the moments of a normally
// distributed (or approximately normal) value.
message DistributionMetric {
- optional double min = 1;
- optional double max = 2;
- optional double mean = 3;
+ optional float min = 1;
+ optional float max = 2;
+ optional float mean = 3;
optional double variance = 4;
- optional double operation_count = 5;
+ optional uint64 operation_count = 5;
// Represents the attributes assocated with this distribution metric
// instance.
@@ -93,9 +66,9 @@
message SessionLifetime {
// Start time of the session in milliseconds since epoch.
- optional int64 start_time_ms = 1;
+ optional uint64 start_time_ms = 1;
// End time of the session in milliseconds since epoch.
- optional int64 end_time_ms = 2;
+ optional uint64 end_time_ms = 2;
}
// The count of open session operations. Each instance has a specific error
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 6b0201a..300c688 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <stdio.h>
+#include <inttypes.h>
#include "DrmPlugin.h"
#include "ClearKeyDrmProperties.h"
@@ -26,6 +27,7 @@
#include "TypeConvert.h"
namespace {
+const int kSecureStopIdStart = 100;
const std::string kStreaming("Streaming");
const std::string kOffline("Offline");
const std::string kTrue("True");
@@ -36,7 +38,18 @@
// Value: "True" or "False"
const std::string kQueryKeyRenewAllowed("RenewAllowed");
// Value: "True" or "False"
-};
+
+const int kSecureStopIdSize = 10;
+
+std::vector<uint8_t> uint32ToVector(uint32_t value) {
+ // 10 bytes to display max value 4294967295 + one byte null terminator
+ char buffer[kSecureStopIdSize];
+ memset(buffer, 0, kSecureStopIdSize);
+ snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
+ return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
+}
+
+}; // unnamed namespace
namespace android {
namespace hardware {
@@ -48,9 +61,11 @@
: mSessionLibrary(sessionLibrary),
mOpenSessionOkCount(0),
mCloseSessionOkCount(0),
- mCloseSessionNotOpenedCount(0) {
+ mCloseSessionNotOpenedCount(0),
+ mNextSecureStopId(kSecureStopIdStart) {
mPlayPolicy.clear();
initProperties();
+ mSecureStops.clear();
}
void DrmPlugin::initProperties() {
@@ -73,6 +88,18 @@
mByteArrayProperties[kMetricsKey] = valueVector;
}
+// The secure stop in ClearKey implementation is not installed securely.
+// This function merely creates a test environment for testing secure stops APIs.
+// The content in this secure stop is implementation dependent, the clearkey
+// secureStop does not serve as a reference implementation.
+void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
+ ClearkeySecureStop clearkeySecureStop;
+ clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
+ clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
+
+ mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(
+ clearkeySecureStop.id, clearkeySecureStop));
+}
Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
sp<Session> session = mSessionLibrary->createSession();
@@ -209,6 +236,7 @@
_hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
return Void();
}
+
sp<Session> session = mSessionLibrary->findSession(toVector(scope));
if (!session.get()) {
_hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
@@ -224,6 +252,8 @@
keySetId.clear();
}
+ installSecureStop(scope);
+
// Returns status and empty keySetId
_hidl_cb(status, toHidlVec(keySetId));
return Void();
@@ -435,7 +465,106 @@
return Void();
}
+Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+ std::vector<SecureStop> stops;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stopVec;
+ stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+ SecureStop stop;
+ stop.opaqueData = toHidlVec(stopVec);
+ stops.push_back(stop);
+ }
+ _hidl_cb(Status::OK, stops);
+ return Void();
+}
+
+Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb) {
+ SecureStop stop;
+ auto itr = mSecureStops.find(toVector(secureStopId));
+ if (itr != mSecureStops.end()) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stopVec;
+ stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+
+ stop.opaqueData = toHidlVec(stopVec);
+ _hidl_cb(Status::OK, stop);
+ } else {
+ _hidl_cb(Status::BAD_VALUE, stop);
+ }
+
+ return Void();
+}
+
+Return<Status> DrmPlugin::releaseSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ return removeSecureStop(secureStopId);
+}
+
+Return<Status> DrmPlugin::releaseAllSecureStops() {
+ return removeAllSecureStops();
+}
+
+Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
+ std::vector<SecureStopId> ids;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ids.push_back(itr->first);
+ }
+
+ _hidl_cb(Status::OK, toHidlVec(ids));
+ return Void();
+}
+
+Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
+ if (ssRelease.opaqueData.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ Status status = Status::OK;
+ std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
+
+ // The format of opaqueData is shared between the server
+ // and the drm service. The clearkey implementation consists of:
+ // count - number of secure stops
+ // list of fixed length secure stops
+ size_t countBufferSize = sizeof(uint32_t);
+ uint32_t count = 0;
+ sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
+
+ // Avoid divide by 0 below.
+ if (count == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ size_t secureStopSize = (input.size() - countBufferSize) / count;
+ uint8_t buffer[secureStopSize];
+ size_t offset = countBufferSize; // skip the count
+ for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
+ memcpy(buffer, input.data() + offset, secureStopSize);
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+
+ status = removeSecureStop(toHidlVec(id));
+ if (Status::OK != status) break;
+ }
+
+ return status;
+}
+
+Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ if (1 != mSecureStops.erase(toVector(secureStopId))) {
+ return Status::BAD_VALUE;
+ }
+ return Status::OK;
+}
+
+Return<Status> DrmPlugin::removeAllSecureStops() {
+ mSecureStops.clear();
+ mNextSecureStopId = kSecureStopIdStart;
+ return Status::OK;
+}
} // namespace clearkey
} // namespace V1_1
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 19baf0b..fb0695a 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -17,9 +17,11 @@
#ifndef CLEARKEY_DRM_PLUGIN_H_
#define CLEARKEY_DRM_PLUGIN_H_
-
#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <stdio.h>
+#include <map>
+
#include "SessionLibrary.h"
#include "Utils.h"
@@ -36,6 +38,7 @@
using ::android::hardware::drm::V1_0::KeyValue;
using ::android::hardware::drm::V1_0::SecureStop;
using ::android::hardware::drm::V1_0::SecureStopId;
+using ::android::hardware::drm::V1_0::SessionId;
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_1::DrmMetricGroup;
using ::android::hardware::drm::V1_1::IDrmPlugin;
@@ -124,34 +127,6 @@
return Void();
}
- Return<void> getSecureStops(getSecureStops_cb _hidl_cb) {
- _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<SecureStop>());
- return Void();
- }
-
- Return<void> getSecureStop(
- const hidl_vec<uint8_t>& secureStopId,
- getSecureStop_cb _hidl_cb) {
-
- if (secureStopId.size() == 0) {
- _hidl_cb(Status::BAD_VALUE, SecureStop());
- return Void();
- }
- _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, SecureStop());
- return Void();
- }
-
- Return<Status> releaseSecureStop(const hidl_vec<uint8_t>& ssRelease) {
- if (ssRelease.size() == 0) {
- return Status::BAD_VALUE;
- }
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
-
- Return<Status> releaseAllSecureStops() {
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
-
Return<void> getHdcpLevels(getHdcpLevels_cb _hidl_cb) {
HdcpLevel connectedLevel = HdcpLevel::HDCP_NONE;
HdcpLevel maxLevel = HdcpLevel::HDCP_NO_OUTPUT;
@@ -305,31 +280,26 @@
return Void();
}
- Return<void> getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
- _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<SecureStopId>());
- return Void();
- }
+ Return<void> getSecureStops(getSecureStops_cb _hidl_cb);
- Return<Status> releaseSecureStops(const SecureStopRelease& ssRelease) {
- if (ssRelease.opaqueData.size() == 0) {
- return Status::BAD_VALUE;
- }
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
+ Return<void> getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb);
- Return<Status> removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
- if (secureStopId.size() == 0) {
- return Status::BAD_VALUE;
- }
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
+ Return<Status> releaseSecureStop(const hidl_vec<uint8_t>& ssRelease);
- Return<Status> removeAllSecureStops() {
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
+ Return<Status> releaseAllSecureStops();
+
+ Return<void> getSecureStopIds(getSecureStopIds_cb _hidl_cb);
+
+ Return<Status> releaseSecureStops(const SecureStopRelease& ssRelease);
+
+ Return<Status> removeSecureStop(const hidl_vec<uint8_t>& secureStopId);
+
+ Return<Status> removeAllSecureStops();
private:
void initProperties();
+ void installSecureStop(const hidl_vec<uint8_t>& sessionId);
void setPlayPolicy();
Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
@@ -344,6 +314,12 @@
KeyRequestType *getKeyRequestType,
std::string *defaultUrl);
+ struct ClearkeySecureStop {
+ std::vector<uint8_t> id;
+ std::vector<uint8_t> data;
+ };
+
+ std::map<std::vector<uint8_t>, ClearkeySecureStop> mSecureStops;
std::vector<KeyValue> mPlayPolicy;
std::map<std::string, std::string> mStringProperties;
std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
@@ -353,6 +329,7 @@
int64_t mOpenSessionOkCount;
int64_t mCloseSessionOkCount;
int64_t mCloseSessionNotOpenedCount;
+ uint32_t mNextSecureStopId;
CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
};
diff --git a/include/media/ExtractorUtils.h b/include/media/ExtractorUtils.h
new file mode 120000
index 0000000..e2dd082
--- /dev/null
+++ b/include/media/ExtractorUtils.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/ExtractorUtils.h
\ No newline at end of file
diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h
new file mode 120000
index 0000000..e3ef134
--- /dev/null
+++ b/include/media/TimeCheck.h
@@ -0,0 +1 @@
+../../media/libmedia/include/media/TimeCheck.h
\ No newline at end of file
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 3f832bc..fc60fd4 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -22,6 +22,7 @@
#include "MatroskaExtractor.h"
#include <media/DataSourceBase.h>
+#include <media/ExtractorUtils.h>
#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -1108,7 +1109,7 @@
meta.setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize);
int32_t maxInputSize = 64 << 10;
- sp<FLACDecoder> flacDecoder = FLACDecoder::Create();
+ FLACDecoder *flacDecoder = FLACDecoder::Create();
if (flacDecoder != NULL
&& flacDecoder->parseMetadata((const uint8_t*)codecPrivate, codecPrivateSize) == OK) {
FLAC__StreamMetadata_StreamInfo streamInfo = flacDecoder->getStreamInfo();
@@ -1120,6 +1121,7 @@
&& streamInfo.channels != 0
&& ((streamInfo.bits_per_sample + 7) / 8) >
INT32_MAX / streamInfo.max_blocksize / streamInfo.channels) {
+ delete flacDecoder;
return ERROR_MALFORMED;
}
maxInputSize = ((streamInfo.bits_per_sample + 7) / 8)
@@ -1128,6 +1130,7 @@
}
meta.setInt32(kKeyMaxInputSize, maxInputSize);
+ delete flacDecoder;
return OK;
}
@@ -1143,13 +1146,13 @@
}
const mkvparser::Block::Frame &frame = block->GetFrame(0);
- sp<ABuffer> abuf = new ABuffer(frame.len);
- long n = frame.Read(mReader, abuf->data());
+ auto tmpData = heapbuffer<unsigned char>(frame.len);
+ long n = frame.Read(mReader, tmpData.get());
if (n != 0) {
return ERROR_MALFORMED;
}
- if (!MakeAVCCodecSpecificData(trackInfo->mMeta, abuf)) {
+ if (!MakeAVCCodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
return ERROR_MALFORMED;
}
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index c082fc1..26b8251 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -76,9 +76,14 @@
Vector<uint32_t> thumbnails;
Vector<uint32_t> dimgRefs;
+ Vector<uint32_t> cdscRefs;
size_t nextTileIndex;
};
+struct ExifItem {
+ off64_t offset;
+ size_t size;
+};
/////////////////////////////////////////////////////////////////////
//
@@ -473,7 +478,9 @@
uint32_t itemId() { return mItemId; }
- void apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const;
+ void apply(
+ KeyedVector<uint32_t, ImageItem> &itemIdToItemMap,
+ KeyedVector<uint32_t, ExifItem> &itemIdToExifMap) const;
private:
uint32_t mItemId;
@@ -483,17 +490,20 @@
DISALLOW_EVIL_CONSTRUCTORS(ItemReference);
};
-void ItemReference::apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const {
- ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
-
- // ignore non-image items
- if (itemIndex < 0) {
- return;
- }
-
+void ItemReference::apply(
+ KeyedVector<uint32_t, ImageItem> &itemIdToItemMap,
+ KeyedVector<uint32_t, ExifItem> &itemIdToExifMap) const {
ALOGV("attach reference type 0x%x to item id %d)", type(), mItemId);
- if (type() == FOURCC('d', 'i', 'm', 'g')) {
+ switch(type()) {
+ case FOURCC('d', 'i', 'm', 'g'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
ImageItem &derivedImage = itemIdToItemMap.editValueAt(itemIndex);
if (!derivedImage.dimgRefs.empty()) {
ALOGW("dimgRefs if not clean!");
@@ -512,7 +522,16 @@
// mark the source image of the derivation as hidden
sourceImage.hidden = true;
}
- } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+ break;
+ }
+ case FOURCC('t', 'h', 'm', 'b'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
// mark thumbnail image as hidden, these can be retrieved if the client
// request thumbnail explicitly, but won't be exposed as displayables.
ImageItem &thumbImage = itemIdToItemMap.editValueAt(itemIndex);
@@ -532,11 +551,43 @@
}
masterImage.thumbnails.push_back(mItemId);
}
- } else if (type() == FOURCC('a', 'u', 'x', 'l')) {
+ break;
+ }
+ case FOURCC('c', 'd', 's', 'c'): {
+ ssize_t itemIndex = itemIdToExifMap.indexOfKey(mItemId);
+
+ // ignore non-exif block items
+ if (itemIndex < 0) {
+ return;
+ }
+
+ for (size_t i = 0; i < mRefs.size(); i++) {
+ itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ continue;
+ }
+ ALOGV("Image item id %d uses metadata item id %d", mRefs[i], mItemId);
+ ImageItem &image = itemIdToItemMap.editValueAt(itemIndex);
+ image.cdscRefs.push_back(mItemId);
+ }
+ break;
+ }
+ case FOURCC('a', 'u', 'x', 'l'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
// mark auxiliary image as hidden
ImageItem &auxImage = itemIdToItemMap.editValueAt(itemIndex);
auxImage.hidden = true;
- } else {
+ break;
+ }
+ default:
ALOGW("ignoring unsupported ref type 0x%x", type());
}
}
@@ -1299,10 +1350,13 @@
for (size_t i = 0; i < mItemInfos.size(); i++) {
const ItemInfo &info = mItemInfos[i];
-
- // ignore non-image items
+ // Only handle 3 types of items, all others are ignored:
+ // 'grid': derived image from tiles
+ // 'hvc1': coded image (or tile)
+ // 'Exif': EXIF metadata
if (info.itemType != FOURCC('g', 'r', 'i', 'd') &&
- info.itemType != FOURCC('h', 'v', 'c', '1')) {
+ info.itemType != FOURCC('h', 'v', 'c', '1') &&
+ info.itemType != FOURCC('E', 'x', 'i', 'f')) {
continue;
}
@@ -1325,6 +1379,19 @@
return ERROR_MALFORMED;
}
+ if (info.itemType == FOURCC('E', 'x', 'i', 'f')) {
+ // Only add if the Exif data is non-empty. The first 4 bytes contain
+ // the offset to TIFF header, which the Exif parser doesn't use.
+ if (size > 4) {
+ ExifItem exifItem = {
+ .offset = offset,
+ .size = size,
+ };
+ mItemIdToExifMap.add(info.itemId, exifItem);
+ }
+ continue;
+ }
+
ImageItem image(info.itemType, info.itemId, info.hidden);
ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
@@ -1354,7 +1421,7 @@
}
for (size_t i = 0; i < mItemReferences.size(); i++) {
- mItemReferences[i]->apply(mItemIdToItemMap);
+ mItemReferences[i]->apply(mItemIdToItemMap, mItemIdToExifMap);
}
bool foundPrimary = false;
@@ -1471,8 +1538,8 @@
// point image to the first tile for grid size and HVCC
image = &mItemIdToItemMap.editValueAt(tileItemIndex);
- meta->setInt32(kKeyGridWidth, image->width);
- meta->setInt32(kKeyGridHeight, image->height);
+ meta->setInt32(kKeyTileWidth, image->width);
+ meta->setInt32(kKeyTileHeight, image->height);
meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
}
@@ -1574,6 +1641,34 @@
return OK;
}
+status_t ItemTable::getExifOffsetAndSize(off64_t *offset, size_t *size) {
+ if (!mImageItemsValid) {
+ return INVALID_OPERATION;
+ }
+
+ ssize_t itemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
+
+ // this should not happen, something's seriously wrong.
+ if (itemIndex < 0) {
+ return INVALID_OPERATION;
+ }
+
+ const ImageItem &image = mItemIdToItemMap[itemIndex];
+ if (image.cdscRefs.size() == 0) {
+ return NAME_NOT_FOUND;
+ }
+
+ ssize_t exifIndex = mItemIdToExifMap.indexOfKey(image.cdscRefs[0]);
+ if (exifIndex < 0) {
+ return NAME_NOT_FOUND;
+ }
+
+ // skip the first 4-byte of the offset to TIFF header
+ *offset = mItemIdToExifMap[exifIndex].offset + 4;
+ *size = mItemIdToExifMap[exifIndex].size - 4;
+ return OK;
+}
+
} // namespace heif
} // namespace android
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index f4a69cc..536dcb0 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -32,6 +32,7 @@
struct AssociationEntry;
struct ImageItem;
+struct ExifItem;
struct ItemLoc;
struct ItemInfo;
struct ItemProperty;
@@ -55,6 +56,7 @@
status_t findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex);
status_t getImageOffsetAndSize(
uint32_t *itemIndex, off64_t *offset, size_t *size);
+ status_t getExifOffsetAndSize(off64_t *offset, size_t *size);
protected:
~ItemTable();
@@ -78,6 +80,7 @@
bool mImageItemsValid;
uint32_t mCurrentItemIndex;
KeyedVector<uint32_t, ImageItem> mItemIdToItemMap;
+ KeyedVector<uint32_t, ExifItem> mItemIdToExifMap;
Vector<uint32_t> mDisplayables;
status_t parseIlocBox(off64_t offset, size_t size);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 78d2ac6..07ef0e3 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -31,6 +31,7 @@
#include "ItemTable.h"
#include "include/ESDS.h"
+#include <media/ExtractorUtils.h>
#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -585,6 +586,12 @@
}
if (mIsHeif && (mItemTable != NULL) && (mItemTable->countImages() > 0)) {
+ off64_t exifOffset;
+ size_t exifSize;
+ if (mItemTable->getExifOffsetAndSize(&exifOffset, &exifSize) == OK) {
+ mFileMetaData.setInt64(kKeyExifOffset, (int64_t)exifOffset);
+ mFileMetaData.setInt64(kKeyExifSize, (int64_t)exifSize);
+ }
for (uint32_t imageIndex = 0;
imageIndex < mItemTable->countImages(); imageIndex++) {
sp<MetaData> meta = mItemTable->getImageMeta(imageIndex);
@@ -600,6 +607,7 @@
ALOGW("Extracting still images only");
err = OK;
}
+ mInitCheck = OK;
ALOGV("adding HEIF image track %u", imageIndex);
Track *track = new Track;
@@ -1324,17 +1332,17 @@
if (mLastTrack == NULL)
return ERROR_MALFORMED;
- sp<ABuffer> buffer = new ABuffer(chunk_data_size);
- if (buffer->data() == NULL) {
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+ if (buffer.get() == NULL) {
return NO_MEMORY;
}
if (mDataSource->readAt(
- data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
+ data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
- String8 mimeFormat((const char *)(buffer->data()), chunk_data_size);
+ String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
mLastTrack->meta.setCString(kKeyMIMEType, mimeFormat.string());
break;
@@ -1833,15 +1841,15 @@
{
*offset += chunk_size;
- sp<ABuffer> buffer = new ABuffer(chunk_data_size);
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
- if (buffer->data() == NULL) {
+ if (buffer.get() == NULL) {
ALOGE("b/28471206");
return NO_MEMORY;
}
if (mDataSource->readAt(
- data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
+ data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
@@ -1849,21 +1857,21 @@
return ERROR_MALFORMED;
mLastTrack->meta.setData(
- kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size);
+ kKeyAVCC, kTypeAVCC, buffer.get(), chunk_data_size);
break;
}
case FOURCC('h', 'v', 'c', 'C'):
{
- sp<ABuffer> buffer = new ABuffer(chunk_data_size);
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
- if (buffer->data() == NULL) {
+ if (buffer.get() == NULL) {
ALOGE("b/28471206");
return NO_MEMORY;
}
if (mDataSource->readAt(
- data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
+ data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
@@ -1871,7 +1879,7 @@
return ERROR_MALFORMED;
mLastTrack->meta.setData(
- kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size);
+ kKeyHVCC, kTypeHVCC, buffer.get(), chunk_data_size);
*offset += chunk_size;
break;
@@ -2212,13 +2220,13 @@
if (chunk_data_size < 0 || static_cast<uint64_t>(chunk_data_size) >= SIZE_MAX - 1) {
return ERROR_MALFORMED;
}
- sp<ABuffer> buffer = new ABuffer(chunk_data_size + 1);
- if (buffer->data() == NULL) {
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+ if (buffer.get() == NULL) {
ALOGE("b/28471206");
return NO_MEMORY;
}
if (mDataSource->readAt(
- data_offset, buffer->data(), chunk_data_size) != (ssize_t)chunk_data_size) {
+ data_offset, buffer.get(), chunk_data_size) != (ssize_t)chunk_data_size) {
return ERROR_IO;
}
const int kSkipBytesOfDataBox = 16;
@@ -2228,7 +2236,7 @@
mFileMetaData.setData(
kKeyAlbumArt, MetaData::TYPE_NONE,
- buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
+ buffer.get() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
break;
}
@@ -2626,16 +2634,16 @@
keySize -= 8;
keyOffset += 8;
- sp<ABuffer> keyData = new ABuffer(keySize);
- if (keyData->data() == NULL) {
+ auto keyData = heapbuffer<uint8_t>(keySize);
+ if (keyData.get() == NULL) {
return ERROR_MALFORMED;
}
if (mDataSource->readAt(
- keyOffset, keyData->data(), keySize) < (ssize_t) keySize) {
+ keyOffset, keyData.get(), keySize) < (ssize_t) keySize) {
return ERROR_MALFORMED;
}
- AString key((const char *)keyData->data(), keySize);
+ AString key((const char *)keyData.get(), keySize);
mMetaKeyMap.add(i, key);
keyOffset += keySize;
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 4d49013..b2fe69c 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -22,6 +22,7 @@
#include <cutils/properties.h>
#include <media/DataSourceBase.h>
+#include <media/ExtractorUtils.h>
#include <media/MediaTrack.h>
#include <media/VorbisComment.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -990,21 +991,11 @@
return OK;
}
-struct TmpData {
- uint8_t *data;
- TmpData(size_t size) {
- data = (uint8_t*) malloc(size);
- }
- ~TmpData() {
- free(data);
- }
-};
-
status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
// add artificial framing bit so we can reuse _vorbis_unpack_comment
int32_t commentSize = buffer->range_length() + 1;
- TmpData commentDataHolder(commentSize);
- uint8_t *commentData = commentDataHolder.data;
+ auto tmp = heapbuffer<uint8_t>(commentSize);
+ uint8_t *commentData = tmp.get();
if (commentData == nullptr) {
return ERROR_MALFORMED;
}
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index 9eed96d..61d7d27 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -64,27 +64,54 @@
* The read and write must be symmetric.
*/
status_t AudioEndpointParcelable::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mNumSharedMemories);
+ status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
+ if (status != NO_ERROR) goto error;
+
+ status = parcel->writeInt32(mNumSharedMemories);
+ if (status != NO_ERROR) goto error;
+
for (int i = 0; i < mNumSharedMemories; i++) {
- mSharedMemories[i].writeToParcel(parcel);
+ status = mSharedMemories[i].writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
}
- mUpMessageQueueParcelable.writeToParcel(parcel);
- mDownMessageQueueParcelable.writeToParcel(parcel);
- mUpDataQueueParcelable.writeToParcel(parcel);
- mDownDataQueueParcelable.writeToParcel(parcel);
- return NO_ERROR; // TODO check for errors above
+ status = mUpMessageQueueParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDownMessageQueueParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mUpDataQueueParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDownDataQueueParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+
+ return NO_ERROR;
+
+error:
+ ALOGE("%s returning %d", __func__, status);
+ return status;
}
status_t AudioEndpointParcelable::readFromParcel(const Parcel* parcel) {
- parcel->readInt32(&mNumSharedMemories);
+ status_t status = parcel->readInt32(&mNumSharedMemories);
+ if (status != NO_ERROR) goto error;
+
for (int i = 0; i < mNumSharedMemories; i++) {
mSharedMemories[i].readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
}
- mUpMessageQueueParcelable.readFromParcel(parcel);
- mDownMessageQueueParcelable.readFromParcel(parcel);
- mUpDataQueueParcelable.readFromParcel(parcel);
- mDownDataQueueParcelable.readFromParcel(parcel);
- return NO_ERROR; // TODO check for errors above
+ status = mUpMessageQueueParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDownMessageQueueParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mUpDataQueueParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDownDataQueueParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+
+ return AAudioConvert_aaudioToAndroidStatus(validate());
+
+error:
+ ALOGE("%s returning %d", __func__, status);
+ return status;
}
aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
@@ -109,35 +136,11 @@
return AAudioConvert_androidToAAudioResult(err);
}
-aaudio_result_t AudioEndpointParcelable::validate() {
- aaudio_result_t result;
+aaudio_result_t AudioEndpointParcelable::validate() const {
if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
ALOGE("invalid mNumSharedMemories = %d", mNumSharedMemories);
return AAUDIO_ERROR_INTERNAL;
}
- for (int i = 0; i < mNumSharedMemories; i++) {
- result = mSharedMemories[i].validate();
- if (result != AAUDIO_OK) {
- ALOGE("invalid mSharedMemories[%d] = %d", i, result);
- return result;
- }
- }
- if ((result = mUpMessageQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mUpMessageQueueParcelable = %d", result);
- return result;
- }
- if ((result = mDownMessageQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mDownMessageQueueParcelable = %d", result);
- return result;
- }
- if ((result = mUpDataQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mUpDataQueueParcelable = %d", result);
- return result;
- }
- if ((result = mDownDataQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mDownDataQueueParcelable = %d", result);
- return result;
- }
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index aa8573f..e4f8b9e 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -56,8 +56,6 @@
aaudio_result_t resolve(EndpointDescriptor *descriptor);
- aaudio_result_t validate();
-
aaudio_result_t close();
void dump();
@@ -70,6 +68,8 @@
RingBufferParcelable mDownDataQueueParcelable; // eg. playback
private:
+ aaudio_result_t validate() const;
+
int32_t mNumSharedMemories = 0;
SharedMemoryParcelable mSharedMemories[MAX_SHARED_MEMORIES];
};
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index b3c4934..620edc7 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -121,17 +121,11 @@
ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION passed result %d", result);
return result;
}
- err = parcelable.readFromParcel(&reply);;
+ err = parcelable.readFromParcel(&reply);
if (err != NO_ERROR) {
ALOGE("BpAAudioService::client transact(GET_STREAM_DESCRIPTION) read endpoint %d", err);
return AAudioConvert_androidToAAudioResult(err);
}
- //parcelable.dump();
- result = parcelable.validate();
- if (result != AAUDIO_OK) {
- ALOGE("BpAAudioService::client GET_STREAM_DESCRIPTION validation fails %d", result);
- return result;
- }
return result;
}
@@ -250,6 +244,7 @@
pid_t tid;
int64_t nanoseconds;
aaudio_result_t result;
+ status_t status = NO_ERROR;
ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
switch(code) {
@@ -294,21 +289,20 @@
case GET_STREAM_DESCRIPTION: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ return status;
+ }
aaudio::AudioEndpointParcelable parcelable;
result = getStreamDescription(streamHandle, parcelable);
if (result != AAUDIO_OK) {
return AAudioConvert_aaudioToAndroidStatus(result);
}
- result = parcelable.validate();
- if (result != AAUDIO_OK) {
- ALOGE("BnAAudioService::onTransact getStreamDescription() returns %d", result);
- parcelable.dump();
- return AAudioConvert_aaudioToAndroidStatus(result);
+ status = reply->writeInt32(result);
+ if (status != NO_ERROR) {
+ return status;
}
- reply->writeInt32(result);
- parcelable.writeToParcel(reply);
- return NO_ERROR;
+ return parcelable.writeToParcel(reply);
} break;
case START_STREAM: {
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 2babbff..4996b3f 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <binder/Parcelable.h>
+#include <utility/AAudioUtilities.h>
#include "binding/AAudioServiceDefinitions.h"
#include "binding/SharedRegionParcelable.h"
@@ -79,7 +80,10 @@
* The read and write must be symmetric.
*/
status_t RingBufferParcelable::writeToParcel(Parcel* parcel) const {
- status_t status = parcel->writeInt32(mCapacityInFrames);
+ status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
+ if (status != NO_ERROR) goto error;
+
+ status = parcel->writeInt32(mCapacityInFrames);
if (status != NO_ERROR) goto error;
if (mCapacityInFrames > 0) {
status = parcel->writeInt32(mBytesPerFrame);
@@ -97,7 +101,7 @@
}
return NO_ERROR;
error:
- ALOGE("writeToParcel() error = %d", status);
+ ALOGE("%s returning %d", __func__, status);
return status;
}
@@ -118,9 +122,9 @@
status = mDataParcelable.readFromParcel(parcel);
if (status != NO_ERROR) goto error;
}
- return NO_ERROR;
+ return AAudioConvert_aaudioToAndroidStatus(validate());
error:
- ALOGE("readFromParcel() error = %d", status);
+ ALOGE("%s returning %d", __func__, status);
return status;
}
@@ -151,8 +155,7 @@
return AAUDIO_OK;
}
-aaudio_result_t RingBufferParcelable::validate() {
- aaudio_result_t result;
+aaudio_result_t RingBufferParcelable::validate() const {
if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
ALOGE("invalid mCapacityInFrames = %d", mCapacityInFrames);
return AAUDIO_ERROR_INTERNAL;
@@ -165,18 +168,6 @@
ALOGE("invalid mFramesPerBurst = %d", mFramesPerBurst);
return AAUDIO_ERROR_INTERNAL;
}
- if ((result = mReadCounterParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mReadCounterParcelable = %d", result);
- return result;
- }
- if ((result = mWriteCounterParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mWriteCounterParcelable = %d", result);
- return result;
- }
- if ((result = mDataParcelable.validate()) != AAUDIO_OK) {
- ALOGE("invalid mDataParcelable = %d", result);
- return result;
- }
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index bd562f2..1dbcf07 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -66,11 +66,12 @@
aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
- aaudio_result_t validate();
-
void dump();
private:
+
+ aaudio_result_t validate() const;
+
SharedRegionParcelable mReadCounterParcelable;
SharedRegionParcelable mWriteCounterParcelable;
SharedRegionParcelable mDataParcelable;
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 4e3e5d1..0b0cf77 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -48,7 +48,10 @@
}
status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
- status_t status = parcel->writeInt32(mSizeInBytes);
+ status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
+ if (status != NO_ERROR) return status;
+
+ status = parcel->writeInt32(mSizeInBytes);
if (status != NO_ERROR) return status;
if (mSizeInBytes > 0) {
ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
@@ -61,21 +64,27 @@
status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
status_t status = parcel->readInt32(&mSizeInBytes);
- if (status != NO_ERROR) {
- return status;
- }
+ if (status != NO_ERROR) goto error;
+
if (mSizeInBytes > 0) {
// The Parcel owns the file descriptor and will close it later.
unique_fd mmapFd;
status = parcel->readUniqueFileDescriptor(&mmapFd);
if (status != NO_ERROR) {
ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
- } else {
- // Resolve the memory now while we still have the FD from the Parcel.
- // Closing the FD will not affect the shared memory once mmap() has been called.
- status = AAudioConvert_androidToAAudioResult(resolveSharedMemory(mmapFd));
+ goto error;
}
+
+ // Resolve the memory now while we still have the FD from the Parcel.
+ // Closing the FD will not affect the shared memory once mmap() has been called.
+ aaudio_result_t result = resolveSharedMemory(mmapFd);
+ status = AAudioConvert_aaudioToAndroidStatus(result);
+ if (status != NO_ERROR) goto error;
}
+
+ return AAudioConvert_aaudioToAndroidStatus(validate());
+
+error:
return status;
}
@@ -136,7 +145,7 @@
return mSizeInBytes;
}
-aaudio_result_t SharedMemoryParcelable::validate() {
+aaudio_result_t SharedMemoryParcelable::validate() const {
if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 2a634e0..82c2240 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -61,8 +61,6 @@
int32_t getSizeInBytes();
- aaudio_result_t validate();
-
void dump();
protected:
@@ -74,6 +72,11 @@
android::base::unique_fd mFd;
int32_t mSizeInBytes = 0;
uint8_t *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
+
+private:
+
+ aaudio_result_t validate() const;
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 7aa80bf..c776116 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -24,6 +24,7 @@
#include <binder/Parcelable.h>
#include <aaudio/AAudio.h>
+#include <utility/AAudioUtilities.h>
#include "binding/SharedMemoryParcelable.h"
#include "binding/SharedRegionParcelable.h"
@@ -47,21 +48,38 @@
}
status_t SharedRegionParcelable::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mSizeInBytes);
+ status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
+ if (status != NO_ERROR) goto error;
+
+ status = parcel->writeInt32(mSizeInBytes);
+ if (status != NO_ERROR) goto error;
if (mSizeInBytes > 0) {
- parcel->writeInt32(mSharedMemoryIndex);
- parcel->writeInt32(mOffsetInBytes);
+ status = parcel->writeInt32(mSharedMemoryIndex);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mOffsetInBytes);
+ if (status != NO_ERROR) goto error;
}
- return NO_ERROR; // TODO check for errors above
+ return NO_ERROR;
+
+error:
+ ALOGE("%s returning %d", __func__, status);
+ return status;
}
status_t SharedRegionParcelable::readFromParcel(const Parcel* parcel) {
- parcel->readInt32(&mSizeInBytes);
+ status_t status = parcel->readInt32(&mSizeInBytes);
+ if (status != NO_ERROR) goto error;
if (mSizeInBytes > 0) {
- parcel->readInt32(&mSharedMemoryIndex);
- parcel->readInt32(&mOffsetInBytes);
+ status = parcel->readInt32(&mSharedMemoryIndex);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32(&mOffsetInBytes);
+ if (status != NO_ERROR) goto error;
}
- return NO_ERROR; // TODO check for errors above
+ return AAudioConvert_aaudioToAndroidStatus(validate());
+
+error:
+ ALOGE("%s returning %d", __func__, status);
+ return status;
}
aaudio_result_t SharedRegionParcelable::resolve(SharedMemoryParcelable *memoryParcels,
@@ -78,7 +96,7 @@
return memoryParcel->resolve(mOffsetInBytes, mSizeInBytes, regionAddressPtr);
}
-aaudio_result_t SharedRegionParcelable::validate() {
+aaudio_result_t SharedRegionParcelable::validate() const {
if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index f6babfd..0cd8c04 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -47,14 +47,15 @@
bool isFileDescriptorSafe(SharedMemoryParcelable *memoryParcels);
- aaudio_result_t validate();
-
void dump();
protected:
int32_t mSharedMemoryIndex = -1;
int32_t mOffsetInBytes = 0;
int32_t mSizeInBytes = 0;
+
+private:
+ aaudio_result_t validate() const;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6b25302..2a3e668 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -67,8 +67,6 @@
, mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
, mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
{
- ALOGD("%s - mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
- __func__, mWakeupDelayNanos, mMinimumSleepNanos);
}
AudioStreamInternal::~AudioStreamInternal() {
@@ -231,8 +229,7 @@
aaudio_result_t AudioStreamInternal::close() {
aaudio_result_t result = AAUDIO_OK;
- ALOGD("close(): mServiceStreamHandle = 0x%08X",
- mServiceStreamHandle);
+ ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
// Don't close a stream while it is running.
aaudio_stream_state_t currentState = getState();
@@ -243,8 +240,8 @@
result = waitForStateChange(currentState, &nextState,
timeoutNanoseconds);
if (result != AAUDIO_OK) {
- ALOGE("close() waitForStateChange() returned %d %s",
- result, AAudio_convertResultToText(result));
+ ALOGE("%s() waitForStateChange() returned %d %s",
+ __func__, result, AAudio_convertResultToText(result));
}
}
setState(AAUDIO_STREAM_STATE_CLOSING);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 11b43c3..0c3b1fa 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -57,8 +57,7 @@
return result;
}
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
+ ALOGE("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -70,8 +69,7 @@
aaudio_result_t AudioStreamInternalPlay::requestFlush() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
+ ALOGE("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -86,7 +84,7 @@
// Bump offset so caller does not see the retrograde motion in getFramesRead().
int64_t offset = writeCounter - readCounter;
mFramesOffsetFromService += offset;
- ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
+ ALOGV("%s() readN = %lld, writeN = %lld, offset = %lld", __func__,
(long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
// Force writeCounter to match readCounter.
@@ -100,9 +98,7 @@
// Write the data, block if needed and timeoutMillis > 0
aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
- int64_t timeoutNanoseconds)
-
-{
+ int64_t timeoutNanoseconds) {
return processData((void *)buffer, numFrames, timeoutNanoseconds);
}
@@ -121,7 +117,7 @@
// Still haven't got any timestamps from server.
// Keep waiting until we get some valid timestamps then start writing to the
// current buffer position.
- ALOGD("processDataNow() wait for valid timestamps");
+ ALOGD("%s() wait for valid timestamps", __func__);
// Sleep very briefly and hope we get a timestamp soon.
*wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
ATRACE_END();
@@ -203,8 +199,6 @@
aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
int32_t numFrames) {
- // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
- // buffer, numFrames);
WrappingBuffer wrappingBuffer;
uint8_t *byteBuffer = (uint8_t *) buffer;
int32_t framesLeft = numFrames;
@@ -249,7 +243,6 @@
int32_t framesWritten = numFrames - framesLeft;
mAudioEndpoint.advanceWriteIndex(framesWritten);
- // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
return framesWritten;
}
@@ -268,7 +261,6 @@
} else {
mLastFramesRead = framesRead;
}
- //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
return framesRead;
}
@@ -276,13 +268,13 @@
{
int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
+ mFramesOffsetFromService;
- //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
return framesWritten;
}
// Render audio in the application callback and then write the data to the stream.
void *AudioStreamInternalPlay::callbackLoop() {
+ ALOGD("%s() entering >>>>>>>>>>>>>>>", __func__);
aaudio_result_t result = AAUDIO_OK;
aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
if (!isDataCallbackSet()) return NULL;
@@ -297,7 +289,6 @@
// Write audio data to stream. This is a BLOCKING WRITE!
result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
if ((result != mCallbackFrames)) {
- ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
if (result >= 0) {
// Only wrote some of the frames requested. Must have timed out.
result = AAUDIO_ERROR_TIMEOUT;
@@ -306,13 +297,13 @@
break;
}
} else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
- ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
+ ALOGV("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
break;
}
}
- ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d",
- result, (int) isActive());
+ ALOGD("%s() exiting, result = %d, isActive() = %d <<<<<<<<<<<<<<",
+ __func__, result, (int) isActive());
return NULL;
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index c4465fd..61e03db 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -104,17 +104,17 @@
mErrorCallbackUserData = builder.getErrorCallbackUserData();
// This is very helpful for debugging in the future. Please leave it in.
- ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+ ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
mSampleRate, mSamplesPerFrame, mFormat,
AudioStream_convertSharingModeToShortText(mSharingMode),
(getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
- ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+ ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
mDeviceId,
mSessionId,
mPerformanceMode,
(isDataCallbackSet() ? "ON" : "OFF"),
mFramesPerDataCallback);
- ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
+ ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
mUsage, mContentType, mInputPreset);
return AAUDIO_OK;
@@ -242,6 +242,22 @@
return close();
}
+void AudioStream::setState(aaudio_stream_state_t state) {
+ ALOGV("%s(%p) from %d to %d", __func__, this, mState, state);
+ // CLOSED is a final state
+ if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ ALOGE("%s(%p) tried to set to %d but already CLOSED", __func__, this, state);
+
+ // Once DISCONNECTED, we can only move to CLOSED state.
+ } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
+ && state != AAUDIO_STREAM_STATE_CLOSED) {
+ ALOGE("%s(%p) tried to set to %d but already DISCONNECTED", __func__, this, state);
+
+ } else {
+ mState = state;
+ }
+}
+
aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
aaudio_stream_state_t *nextState,
int64_t timeoutNanoseconds)
@@ -313,7 +329,9 @@
setPeriodNanoseconds(periodNanoseconds);
int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
if (err != 0) {
- return AAudioConvert_androidToAAudioResult(-errno);
+ android::status_t status = -errno;
+ ALOGE("createThread() - pthread_create() failed, %d", status);
+ return AAudioConvert_androidToAAudioResult(status);
} else {
// TODO Use AAudioThread or maybe AndroidThread
// Name the thread with an increasing index, "AAudio_#", for debugging.
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index c0db0f9..5273e36 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -471,16 +471,7 @@
mFormat = format;
}
- void setState(aaudio_stream_state_t state) {
- if (mState == AAUDIO_STREAM_STATE_CLOSED) {
- ; // CLOSED is a final state
- } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
- && state != AAUDIO_STREAM_STATE_CLOSED) {
- ; // Once DISCONNECTED, we can only move to CLOSED state.
- } else {
- mState = state;
- }
- }
+ void setState(aaudio_stream_state_t state);
void setDeviceId(int32_t deviceId) {
mDeviceId = deviceId;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 40b31b9..4a2a0a8 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -597,16 +597,21 @@
}
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
- int32_t bytesPerFrame,
- int32_t *sizeInBytes) {
- // TODO implement more elegantly
- const int32_t maxChannels = 256; // ridiculously large
- const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
- // Prevent overflow by limiting multiplicands.
- if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
+ int32_t bytesPerFrame,
+ int32_t *sizeInBytes) {
+ *sizeInBytes = 0;
+
+ if (numFrames < 0 || bytesPerFrame < 0) {
+ ALOGE("negative size, numFrames = %d, frameSize = %d", numFrames, bytesPerFrame);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ // Prevent numeric overflow.
+ if (numFrames > (INT32_MAX / bytesPerFrame)) {
ALOGE("size overflow, numFrames = %d, frameSize = %d", numFrames, bytesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
+
*sizeInBytes = numFrames * bytesPerFrame;
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index cea88fb..4b975e8 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -196,14 +196,16 @@
/**
* Calculate the number of bytes and prevent numeric overflow.
+ * The *sizeInBytes will be set to zero if there is an error.
+ *
* @param numFrames frame count
* @param bytesPerFrame size of a frame in bytes
- * @param sizeInBytes total size in bytes
+ * @param sizeInBytes pointer to a variable to receive total size in bytes
* @return AAUDIO_OK or negative error, eg. AAUDIO_ERROR_OUT_OF_RANGE
*/
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
- int32_t bytesPerFrame,
- int32_t *sizeInBytes);
+ int32_t bytesPerFrame,
+ int32_t *sizeInBytes);
audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudio_format);
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 3358e35..a20f1f2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,6 +24,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include "IAudioFlinger.h"
@@ -902,13 +903,15 @@
case SET_MODE:
case SET_MIC_MUTE:
case SET_LOW_RAM_DEVICE:
- case SYSTEM_READY:
- if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+ case SYSTEM_READY: {
+ uid_t multiUserClientUid = IPCThreadState::self()->getCallingUid() % AID_USER_OFFSET;
+ if (multiUserClientUid >= AID_APP_START) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
return INVALID_OPERATION;
}
+ } break;
default:
break;
}
@@ -933,6 +936,8 @@
break;
}
+ TimeCheck check("IAudioFlinger");
+
switch (code) {
case CREATE_TRACK: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 8f5ff30..a49b2cb 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -27,6 +27,7 @@
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
+#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include <system/audio.h>
@@ -871,17 +872,34 @@
case INIT_STREAM_VOLUME:
case SET_STREAM_VOLUME:
case REGISTER_POLICY_MIXES:
- case SET_MASTER_MONO:
- if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+ case SET_MASTER_MONO: {
+ uid_t multiUserClientUid = IPCThreadState::self()->getCallingUid() % AID_USER_OFFSET;
+ if (multiUserClientUid >= AID_APP_START) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
return INVALID_OPERATION;
}
+ } break;
default:
break;
}
+ // FIXME: extend timeout for SET_DEVICE_CONNECTION_STATE and HANDLE_DEVICE_CONFIG_CHANGE
+ // while we investigate why BT A2DP device connection/disconnection can sometimes
+ // take more than 5 seconds
+ uint32_t timeoutMs = TimeCheck::kDefaultTimeOutMs;
+ switch (code) {
+ case SET_DEVICE_CONNECTION_STATE:
+ case HANDLE_DEVICE_CONFIG_CHANGE:
+ timeoutMs *= 2;
+ break;
+ default:
+ break;
+ }
+
+ TimeCheck check("IAudioPolicyService", timeoutMs);
+
switch (code) {
case SET_DEVICE_CONNECTION_STATE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 63130c4..8dae251 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -337,8 +337,8 @@
if (frameInfo != nullptr) {
frameInfo->set(
- videoFrame->mDisplayWidth,
- videoFrame->mDisplayHeight,
+ videoFrame->mWidth,
+ videoFrame->mHeight,
videoFrame->mRotationAngle,
videoFrame->mBytesPerPixel,
videoFrame->mIccSize,
@@ -415,8 +415,8 @@
if (frameInfo != nullptr) {
frameInfo->set(
- videoFrame->mDisplayWidth,
- videoFrame->mDisplayHeight,
+ videoFrame->mWidth,
+ videoFrame->mHeight,
videoFrame->mRotationAngle,
videoFrame->mBytesPerPixel,
videoFrame->mIccSize,
@@ -435,12 +435,12 @@
return false;
}
VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
- if (mCurScanline >= videoFrame->mDisplayHeight) {
+ if (mCurScanline >= videoFrame->mHeight) {
ALOGE("no more scanline available");
return false;
}
uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
- memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mDisplayWidth);
+ memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
return true;
}
@@ -452,8 +452,8 @@
uint32_t oldScanline = mCurScanline;
mCurScanline += count;
- if (mCurScanline > videoFrame->mDisplayHeight) {
- mCurScanline = videoFrame->mDisplayHeight;
+ if (mCurScanline > videoFrame->mHeight) {
+ mCurScanline = videoFrame->mHeight;
}
return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
}
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 34b15a8..3990e69 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -18,7 +18,7 @@
vndk: {
enabled: true,
},
- srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+ srcs: ["AudioParameter.cpp", "TypeConverter.cpp", "TimeCheck.cpp"],
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 5418af9..6f56d0c 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -56,10 +56,8 @@
AMEDIAFORMAT_KEY_COLOR_TRANSFER,
AMEDIAFORMAT_KEY_COMPLEXITY,
AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,
- AMEDIAFORMAT_KEY_GRID_COLS,
- AMEDIAFORMAT_KEY_GRID_HEIGHT,
+ AMEDIAFORMAT_KEY_GRID_COLUMNS,
AMEDIAFORMAT_KEY_GRID_ROWS,
- AMEDIAFORMAT_KEY_GRID_WIDTH,
AMEDIAFORMAT_KEY_HEIGHT,
AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD,
AMEDIAFORMAT_KEY_IS_ADTS,
@@ -84,6 +82,8 @@
AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
AMEDIAFORMAT_KEY_DISPLAY_WIDTH,
AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID,
+ AMEDIAFORMAT_KEY_TILE_HEIGHT,
+ AMEDIAFORMAT_KEY_TILE_WIDTH,
AMEDIAFORMAT_KEY_TRACK_INDEX,
};
@@ -1068,6 +1068,14 @@
return OK;
}
+status_t AMediaExtractorWrapper::disconnect() {
+ if (mAMediaExtractor != NULL) {
+ media_status_t err = AMediaExtractor_disconnect(mAMediaExtractor);
+ return translateErrorCode(err);
+ }
+ return DEAD_OBJECT;
+}
+
AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
return mAMediaExtractor;
}
diff --git a/media/libmedia/TimeCheck.cpp b/media/libmedia/TimeCheck.cpp
new file mode 100644
index 0000000..dab5d4f
--- /dev/null
+++ b/media/libmedia/TimeCheck.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+
+#include <media/TimeCheck.h>
+
+namespace android {
+
+/* static */
+sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
+{
+ static sp<TimeCheck::TimeCheckThread> sTimeCheckThread = new TimeCheck::TimeCheckThread();
+ return sTimeCheckThread;
+}
+
+TimeCheck::TimeCheck(const char *tag, uint32_t timeoutMs)
+ : mEndTimeNs(getTimeCheckThread()->startMonitoring(tag, timeoutMs))
+{
+}
+
+TimeCheck::~TimeCheck() {
+ getTimeCheckThread()->stopMonitoring(mEndTimeNs);
+}
+
+TimeCheck::TimeCheckThread::~TimeCheckThread()
+{
+ AutoMutex _l(mMutex);
+ requestExit();
+ mMonitorRequests.clear();
+ mCond.signal();
+}
+
+nsecs_t TimeCheck::TimeCheckThread::startMonitoring(const char *tag, uint32_t timeoutMs) {
+ Mutex::Autolock _l(mMutex);
+ nsecs_t endTimeNs = systemTime() + milliseconds(timeoutMs);
+ for (; mMonitorRequests.indexOfKey(endTimeNs) >= 0; ++endTimeNs);
+ mMonitorRequests.add(endTimeNs, tag);
+ mCond.signal();
+ return endTimeNs;
+}
+
+void TimeCheck::TimeCheckThread::stopMonitoring(nsecs_t endTimeNs) {
+ Mutex::Autolock _l(mMutex);
+ mMonitorRequests.removeItem(endTimeNs);
+ mCond.signal();
+}
+
+bool TimeCheck::TimeCheckThread::threadLoop()
+{
+ status_t status = TIMED_OUT;
+ const char *tag;
+ {
+ AutoMutex _l(mMutex);
+
+ if (exitPending()) {
+ return false;
+ }
+
+ nsecs_t endTimeNs = INT64_MAX;
+ // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
+ if (mMonitorRequests.size() != 0) {
+ endTimeNs = mMonitorRequests.keyAt(0);
+ tag = mMonitorRequests.valueAt(0);
+ }
+
+ const nsecs_t waitTimeNs = endTimeNs - systemTime();
+ if (waitTimeNs > 0) {
+ status = mCond.waitRelative(mMutex, waitTimeNs);
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
+ return true;
+}
+
+}; // namespace android
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 9323d6d..03700bf 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -226,8 +226,12 @@
MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_BACK),
MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT4),
MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT4),
TERMINATOR
};
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index b0e1cc8..f267f76 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -182,6 +182,7 @@
const Vector<sp<IDrmFactory>> mFactories;
sp<IDrmPlugin> mPlugin;
sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ String8 mAppPackageName;
// Mutable to allow modification within GetPropertyByteArray.
mutable MediaDrmMetrics mMetrics;
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 191665a..c97d171 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -287,6 +287,8 @@
status_t release();
+ status_t disconnect();
+
status_t setDataSource(int fd, off64_t offset, off64_t length);
status_t setDataSource(const char *location);
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
index 4a5a363..e00bd43 100644
--- a/media/libmedia/include/media/PluginMetricsReporting.h
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -20,13 +20,13 @@
#include <utils/Errors.h>
#include <utils/String8.h>
-#include <utils/Vector.h>
namespace android {
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendorName,
- const String8& description);
+ const String8& description,
+ const String8& appPackageName);
} // namespace android
diff --git a/media/libmedia/include/media/TimeCheck.h b/media/libmedia/include/media/TimeCheck.h
new file mode 100644
index 0000000..6c5f656
--- /dev/null
+++ b/media/libmedia/include/media/TimeCheck.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+
+#ifndef ANDROID_TIME_CHECK_H
+#define ANDROID_TIME_CHECK_H
+
+#include <utils/KeyedVector.h>
+#include <utils/Thread.h>
+
+
+namespace android {
+
+// A class monitoring execution time for a code block (scoped variable) and causing an assert
+// if it exceeds a certain time
+
+class TimeCheck {
+public:
+
+ // The default timeout is chosen to be less than system server watchdog timeout
+ static constexpr uint32_t kDefaultTimeOutMs = 5000;
+
+ TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
+ ~TimeCheck();
+
+private:
+
+ class TimeCheckThread : public Thread {
+ public:
+
+ TimeCheckThread() {}
+ virtual ~TimeCheckThread() override;
+
+ nsecs_t startMonitoring(const char *tag, uint32_t timeoutMs);
+ void stopMonitoring(nsecs_t endTimeNs);
+
+ private:
+
+ // RefBase
+ virtual void onFirstRef() override { run("TimeCheckThread", PRIORITY_URGENT_AUDIO); }
+
+ // Thread
+ virtual bool threadLoop() override;
+
+ Condition mCond;
+ Mutex mMutex;
+ // using the end time in ns as key is OK given the risk is low that two entries
+ // are added in such a way that <add time> + <timeout> are the same for both.
+ KeyedVector< nsecs_t, const char*> mMonitorRequests;
+ };
+
+ static sp<TimeCheckThread> getTimeCheckThread();
+
+ const nsecs_t mEndTimeNs;
+};
+
+}; // namespace android
+
+#endif // ANDROID_TIME_CHECK_H
diff --git a/media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h b/media/libmediaextractor/include/media/ExtractorUtils.h
similarity index 65%
rename from media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h
rename to media/libmediaextractor/include/media/ExtractorUtils.h
index ea0b5c4..22f9349 100644
--- a/media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h
+++ b/media/libmediaextractor/include/media/ExtractorUtils.h
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-#ifndef CODEC2_INFO_BUILDER_H_
-#define CODEC2_INFO_BUILDER_H_
+#ifndef EXTRACTOR_UTILS_H_
-#include <media/stagefright/MediaCodecList.h>
-#include <utils/Errors.h>
+#define EXTRACTOR_UTILS_H_
+
+#include <memory>
namespace android {
-class Codec2InfoBuilder : public MediaCodecListBuilderBase {
-public:
- Codec2InfoBuilder() = default;
- status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
-};
+template <class T>
+std::unique_ptr<T[]> heapbuffer(size_t size) {
+ return std::unique_ptr<T[]>(new (std::nothrow) T[size]);
+}
} // namespace android
-#endif // CODEC2_INFO_BUILDER_H_
+#endif // UTILS_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 6010af4..f1b7806 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -211,13 +211,15 @@
kKeyTemporalLayerId = 'iLyr', // int32_t, temporal layer-id. 0-based (0 => base layer)
kKeyTemporalLayerCount = 'cLyr', // int32_t, number of temporal layers encoded
- kKeyGridWidth = 'grdW', // int32_t, HEIF grid width
- kKeyGridHeight = 'grdH', // int32_t, HEIF grid height
+ kKeyTileWidth = 'tilW', // int32_t, HEIF tile width
+ kKeyTileHeight = 'tilH', // int32_t, HEIF tile height
kKeyGridRows = 'grdR', // int32_t, HEIF grid rows
kKeyGridCols = 'grdC', // int32_t, HEIF grid columns
- kKeyIccProfile = 'prof', // raw data, ICC prifile data
+ kKeyIccProfile = 'prof', // raw data, ICC profile data
kKeyIsPrimaryImage = 'prim', // bool (int32_t), image track is the primary image
kKeyFrameCount = 'nfrm', // int32_t, total number of frame in video track
+ kKeyExifOffset = 'exof', // int64_t, Exif data offset
+ kKeyExifSize = 'exsz', // int64_t, Exif data size
};
enum {
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 9e96a2b..e5567dc 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -903,7 +903,6 @@
if (mPlayer == 0) {
return INVALID_OPERATION;
}
- return mPlayer->getPlaybackSettings(rate);
status_t ret = mPlayer->getPlaybackSettings(rate);
if (ret == NO_ERROR) {
ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
@@ -925,7 +924,9 @@
status_t MediaPlayer2::getSyncSettings(
AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
+ }
status_t ret = mPlayer->getSyncSettings(sync, videoFps);
if (ret == NO_ERROR) {
ALOGV("getSyncSettings(%u, %u, %f, %f)",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b296622..a8c6d15 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -37,7 +37,6 @@
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodec.h>
-#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/PersistentSurface.h>
@@ -553,6 +552,7 @@
mNativeWindowUsageBits(0),
mLastNativeWindowDataSpace(HAL_DATASPACE_UNKNOWN),
mIsVideo(false),
+ mIsImage(false),
mIsEncoder(false),
mFatalError(false),
mShutdownInProgress(false),
@@ -1713,6 +1713,7 @@
mIsEncoder = encoder;
mIsVideo = !strncasecmp(mime, "video/", 6);
+ mIsImage = !strncasecmp(mime, "image/", 6);
mPortMode[kPortIndexInput] = IOMX::kPortModePresetByteBuffer;
mPortMode[kPortIndexOutput] = IOMX::kPortModePresetByteBuffer;
@@ -1728,10 +1729,11 @@
// FLAC encoder or video encoder in constant quality mode doesn't need a
// bitrate, other encoders do.
if (encoder) {
- if (mIsVideo && !findVideoBitrateControlInfo(
- msg, &bitrateMode, &bitrate, &quality)) {
- return INVALID_OPERATION;
- } else if (!mIsVideo && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)
+ if (mIsVideo || mIsImage) {
+ if (!findVideoBitrateControlInfo(msg, &bitrateMode, &bitrate, &quality)) {
+ return INVALID_OPERATION;
+ }
+ } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)
&& !msg->findInt32("bitrate", &bitrate)) {
return INVALID_OPERATION;
}
@@ -2010,7 +2012,7 @@
(void)msg->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
// invalid encodings will default to PCM-16bit in setupRawAudioFormat.
- if (mIsVideo) {
+ if (mIsVideo || mIsImage) {
// determine need for software renderer
bool usingSwRenderer = false;
if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
@@ -2290,7 +2292,7 @@
}
// create data converters if needed
- if (!mIsVideo && err == OK) {
+ if (!mIsVideo && !mIsImage && err == OK) {
AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;
if (encoder) {
(void)mInputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
@@ -3215,6 +3217,7 @@
{ MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 },
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
{ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
+ { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, OMX_VIDEO_CodingImageHEIC },
};
static status_t GetVideoCodingTypeFromMime(
@@ -3872,7 +3875,8 @@
break;
case OMX_VIDEO_CodingHEVC:
- err = setupHEVCEncoderParameters(msg);
+ case OMX_VIDEO_CodingImageHEIC:
+ err = setupHEVCEncoderParameters(msg, outputFormat);
break;
case OMX_VIDEO_CodingVP8:
@@ -4378,27 +4382,63 @@
return configureBitrate(bitrateMode, bitrate);
}
-status_t ACodec::setupHEVCEncoderParameters(const sp<AMessage> &msg) {
- float iFrameInterval;
- if (!msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
- return INVALID_OPERATION;
+status_t ACodec::configureImageGrid(
+ const sp<AMessage> &msg, sp<AMessage> &outputFormat) {
+ int32_t tileWidth, tileHeight, gridRows, gridCols;
+ if (!msg->findInt32("tile-width", &tileWidth) ||
+ !msg->findInt32("tile-height", &tileHeight) ||
+ !msg->findInt32("grid-rows", &gridRows) ||
+ !msg->findInt32("grid-cols", &gridCols)) {
+ return OK;
}
+ OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE gridType;
+ InitOMXParams(&gridType);
+ gridType.nPortIndex = kPortIndexOutput;
+ gridType.bEnabled = OMX_TRUE;
+ gridType.nTileWidth = tileWidth;
+ gridType.nTileHeight = tileHeight;
+ gridType.nGridRows = gridRows;
+ gridType.nGridCols = gridCols;
+
+ status_t err = mOMXNode->setParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidImageGrid,
+ &gridType, sizeof(gridType));
+
+ // for video encoders, grid config is only a hint.
+ if (!mIsImage) {
+ return OK;
+ }
+
+ // image encoders must support grid config.
+ if (err != OK) {
+ return err;
+ }
+
+ // query to get the image encoder's real grid config as it might be
+ // different from the requested, and transfer that to the output.
+ err = mOMXNode->getParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidImageGrid,
+ &gridType, sizeof(gridType));
+
+ if (err == OK && gridType.bEnabled) {
+ outputFormat->setInt32("tile-width", gridType.nTileWidth);
+ outputFormat->setInt32("tile-height", gridType.nTileHeight);
+ outputFormat->setInt32("grid-rows", gridType.nGridRows);
+ outputFormat->setInt32("grid-cols", gridType.nGridCols);
+ }
+
+ return err;
+}
+
+status_t ACodec::setupHEVCEncoderParameters(
+ const sp<AMessage> &msg, sp<AMessage> &outputFormat) {
OMX_VIDEO_CONTROLRATETYPE bitrateMode;
int32_t bitrate, quality;
if (!findVideoBitrateControlInfo(msg, &bitrateMode, &bitrate, &quality)) {
return INVALID_OPERATION;
}
- float frameRate;
- if (!msg->findFloat("frame-rate", &frameRate)) {
- int32_t tmp;
- if (!msg->findInt32("frame-rate", &tmp)) {
- return INVALID_OPERATION;
- }
- frameRate = (float)tmp;
- }
-
OMX_VIDEO_PARAM_HEVCTYPE hevcType;
InitOMXParams(&hevcType);
hevcType.nPortIndex = kPortIndexOutput;
@@ -4426,7 +4466,27 @@
hevcType.eLevel = static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level);
}
// TODO: finer control?
- hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate) + 1;
+ if (mIsImage) {
+ hevcType.nKeyFrameInterval = 1;
+ } else {
+ float iFrameInterval;
+ if (!msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
+ return INVALID_OPERATION;
+ }
+
+ float frameRate;
+ if (!msg->findFloat("frame-rate", &frameRate)) {
+ int32_t tmp;
+ if (!msg->findInt32("frame-rate", &tmp)) {
+ return INVALID_OPERATION;
+ }
+ frameRate = (float)tmp;
+ }
+
+ hevcType.nKeyFrameInterval =
+ setPFramesSpacing(iFrameInterval, frameRate) + 1;
+ }
+
err = mOMXNode->setParameter(
(OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType));
@@ -4434,6 +4494,12 @@
return err;
}
+ err = configureImageGrid(msg, outputFormat);
+
+ if (err != OK) {
+ return err;
+ }
+
return configureBitrate(bitrateMode, bitrate, quality);
}
@@ -4875,7 +4941,8 @@
(void)getHDRStaticInfoForVideoCodec(kPortIndexInput, notify);
}
uint32_t latency = 0;
- if (mIsEncoder && getLatency(&latency) == OK && latency > 0) {
+ if (mIsEncoder && !mIsImage &&
+ getLatency(&latency) == OK && latency > 0) {
notify->setInt32("latency", latency);
}
}
@@ -4931,7 +4998,8 @@
notify->setString("mime", mime.c_str());
}
uint32_t intraRefreshPeriod = 0;
- if (mIsEncoder && getIntraRefreshPeriod(&intraRefreshPeriod) == OK
+ if (mIsEncoder && !mIsImage &&
+ getIntraRefreshPeriod(&intraRefreshPeriod) == OK
&& intraRefreshPeriod > 0) {
notify->setInt32("intra-refresh-period", intraRefreshPeriod);
}
@@ -6346,37 +6414,19 @@
sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
- Vector<AString> matchingCodecs;
- Vector<AString> owners;
-
- AString componentName;
- CHECK(msg->findString("componentName", &componentName));
-
- sp<IMediaCodecList> list = MediaCodecList::getInstance();
- if (list == nullptr) {
- ALOGE("Unable to obtain MediaCodecList while "
- "attempting to create codec \"%s\"",
- componentName.c_str());
- mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
- return false;
- }
- ssize_t index = list->findCodecByName(componentName.c_str());
- if (index < 0) {
- ALOGE("Unable to find codec \"%s\"",
- componentName.c_str());
- mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
- return false;
- }
- sp<MediaCodecInfo> info = list->getCodecInfo(index);
+ sp<RefBase> obj;
+ CHECK(msg->findObject("codecInfo", &obj));
+ sp<MediaCodecInfo> info = (MediaCodecInfo *)obj.get();
if (info == nullptr) {
- ALOGE("Unexpected error (index out-of-bound) while "
- "retrieving information for codec \"%s\"",
- componentName.c_str());
+ ALOGE("Unexpected nullptr for codec information");
mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
return false;
}
AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();
+ AString componentName;
+ CHECK(msg->findString("componentName", &componentName));
+
sp<CodecObserver> observer = new CodecObserver;
sp<IOMX> omx;
sp<IOMXNode> omxNode;
@@ -8226,8 +8276,9 @@
}
bool isVideo = strncasecmp(mime, "video/", 6) == 0;
+ bool isImage = strncasecmp(mime, "image/", 6) == 0;
- if (isVideo) {
+ if (isVideo || isImage) {
OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
InitOMXParams(¶m);
param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 13d80f5..22b1e59 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -49,6 +49,44 @@
}
cc_library_shared {
+ name: "libstagefright_codecbase",
+
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "CodecBase.cpp",
+ "FrameRenderTracker.cpp",
+ "MediaCodecListWriter.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ shared_libs: [
+ "libgui",
+ "liblog",
+ "libmedia_omx",
+ "libstagefright_foundation",
+ "libui",
+ "libutils",
+ "android.hardware.cas.native@1.0",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ diag: {
+ cfi: true,
+ },
+ },
+}
+
+cc_library_shared {
name: "libstagefright",
srcs: [
@@ -60,11 +98,6 @@
"AudioPresentationInfo.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
- "C2OMXNode.cpp",
- "CCodec.cpp",
- "CCodecBufferChannel.cpp",
- "Codec2InfoBuilder.cpp",
- "CodecBase.cpp",
"CallbackDataSource.cpp",
"CallbackMediaSource.cpp",
"CameraSource.cpp",
@@ -74,7 +107,6 @@
"DataURISource.cpp",
"FileSource.cpp",
"FrameDecoder.cpp",
- "FrameRenderTracker.cpp",
"HTTPBase.cpp",
"HevcUtils.cpp",
"InterfaceUtils.cpp",
@@ -101,16 +133,13 @@
"SkipCutBuffer.cpp",
"StagefrightMediaScanner.cpp",
"StagefrightMetadataRetriever.cpp",
+ "StagefrightPluginLoader.cpp",
"SurfaceUtils.cpp",
"Utils.cpp",
"ThrottledSource.cpp",
"VideoFrameScheduler.cpp",
],
- header_libs: [
- "libstagefright_codec2_internal",
- ],
-
shared_libs: [
"libaudioutils",
"libbinder",
@@ -131,8 +160,7 @@
"libui",
"libutils",
"libmedia_helper",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
+ "libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx",
"libstagefright_omx_utils",
@@ -141,18 +169,12 @@
"libhidlallocatorutils",
"libhidlbase",
"libhidlmemory",
- // TODO: Remove libv4l2_c2_componentstore.
- "libv4l2_c2componentstore",
"libziparchive",
"android.hidl.allocator@1.0",
"android.hardware.cas.native@1.0",
"android.hardware.media.omx@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
-
- // TODO: do not link directly with impl
- "android.hardware.media.c2@1.0-service-impl",
- "libstagefright_bufferqueue_helper",
],
static_libs: [
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 7b3fa02..b760273 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -24,7 +24,6 @@
#include <media/ICrypto.h>
#include <utils/NativeHandle.h>
-#include "include/Codec2Buffer.h"
#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
@@ -64,592 +63,4 @@
return ICrypto::kDestinationTypeNativeHandle;
}
-// Codec2Buffer
-
-bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
- if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
- return false;
- }
- if (!buffer) {
- // Nothing to copy, so we can copy by doing nothing.
- return true;
- }
- if (buffer->data().type() != C2BufferData::LINEAR) {
- return false;
- }
- if (buffer->data().linearBlocks().size() == 0u) {
- // Nothing to copy, so we can copy by doing nothing.
- return true;
- } else if (buffer->data().linearBlocks().size() > 1u) {
- // We don't know how to copy more than one blocks.
- return false;
- }
- if (buffer->data().linearBlocks()[0].size() > capacity()) {
- // It won't fit.
- return false;
- }
- return true;
-}
-
-bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
- // We assume that all canCopyLinear() checks passed.
- if (!buffer || buffer->data().linearBlocks().size() == 0u) {
- setRange(0, 0);
- return true;
- }
- C2ReadView view = buffer->data().linearBlocks()[0].map().get();
- if (view.error() != C2_OK) {
- ALOGD("Error while mapping: %d", view.error());
- return false;
- }
- if (view.capacity() > capacity()) {
- ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
- view.capacity(), capacity());
- return false;
- }
- memcpy(base(), view.data(), view.capacity());
- setRange(0, view.capacity());
- return true;
-}
-
-// LocalLinearBuffer
-
-bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
- return canCopyLinear(buffer);
-}
-
-bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
- return copyLinear(buffer);
-}
-
-// DummyContainerBuffer
-
-DummyContainerBuffer::DummyContainerBuffer(
- const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
- : Codec2Buffer(format, new ABuffer(nullptr, 1)),
- mBufferRef(buffer) {
- setRange(0, buffer ? 1 : 0);
-}
-
-std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
- return std::move(mBufferRef);
-}
-
-bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
- return !mBufferRef;
-}
-
-bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
- mBufferRef = buffer;
- setRange(0, mBufferRef ? 1 : 0);
- return true;
-}
-
-// LinearBlockBuffer
-
-// static
-sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
- const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
- C2WriteView writeView(block->map().get());
- if (writeView.error() != C2_OK) {
- return nullptr;
- }
- return new LinearBlockBuffer(format, std::move(writeView), block);
-}
-
-std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
- return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
-}
-
-bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
- return canCopyLinear(buffer);
-}
-
-bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
- return copyLinear(buffer);
-}
-
-LinearBlockBuffer::LinearBlockBuffer(
- const sp<AMessage> &format,
- C2WriteView&& writeView,
- const std::shared_ptr<C2LinearBlock> &block)
- : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
- mWriteView(writeView),
- mBlock(block) {
-}
-
-// ConstLinearBlockBuffer
-
-// static
-sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
- const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
- if (!buffer
- || buffer->data().type() != C2BufferData::LINEAR
- || buffer->data().linearBlocks().size() != 1u) {
- return nullptr;
- }
- C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
- if (readView.error() != C2_OK) {
- return nullptr;
- }
- return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
-}
-
-ConstLinearBlockBuffer::ConstLinearBlockBuffer(
- const sp<AMessage> &format,
- C2ReadView&& readView,
- const std::shared_ptr<C2Buffer> &buffer)
- : Codec2Buffer(format, new ABuffer(
- // NOTE: ABuffer only takes non-const pointer but this data is
- // supposed to be read-only.
- const_cast<uint8_t *>(readView.data()), readView.capacity())),
- mReadView(readView),
- mBufferRef(buffer) {
-}
-
-std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
- return std::move(mBufferRef);
-}
-
-// GraphicView2MediaImageConverter
-
-namespace {
-
-class GraphicView2MediaImageConverter {
-public:
- explicit GraphicView2MediaImageConverter(const C2GraphicView &view)
- : mInitCheck(NO_INIT),
- mView(view),
- mWidth(view.width()),
- mHeight(view.height()),
- mAllocatedDepth(0),
- mBackBufferSize(0),
- mMediaImage(new ABuffer(sizeof(MediaImage2))) {
- if (view.error() != C2_OK) {
- ALOGD("Converter: view.error() = %d", view.error());
- mInitCheck = BAD_VALUE;
- return;
- }
- MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
- const C2PlanarLayout &layout = view.layout();
- if (layout.numPlanes == 0) {
- ALOGD("Converter: 0 planes");
- mInitCheck = BAD_VALUE;
- return;
- }
- mAllocatedDepth = layout.planes[0].allocatedDepth;
- uint32_t bitDepth = layout.planes[0].bitDepth;
-
- switch (layout.type) {
- case C2PlanarLayout::TYPE_YUV:
- mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV; break;
- case C2PlanarLayout::TYPE_YUVA:
- mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA; break;
- case C2PlanarLayout::TYPE_RGB:
- mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB; break;
- case C2PlanarLayout::TYPE_RGBA:
- mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA; break;
- default:
- mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN; break;
- }
- mediaImage->mNumPlanes = layout.numPlanes;
- mediaImage->mWidth = mWidth;
- mediaImage->mHeight = mHeight;
- mediaImage->mBitDepth = bitDepth;
- mediaImage->mBitDepthAllocated = mAllocatedDepth;
-
- uint32_t bufferSize = 0;
- for (uint32_t i = 0; i < layout.numPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- if (plane.rightShift != 0) {
- ALOGV("rightShift value of %u unsupported", plane.rightShift);
- mInitCheck = BAD_VALUE;
- return;
- }
- if (plane.endianness != C2PlaneInfo::NATIVE) {
- ALOGV("endianness value of %u unsupported", plane.endianness);
- mInitCheck = BAD_VALUE;
- return;
- }
- if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
- ALOGV("different allocatedDepth/bitDepth per plane unsupported");
- mInitCheck = BAD_VALUE;
- return;
- }
- bufferSize += mWidth * mHeight
- / plane.rowSampling / plane.colSampling * (plane.allocatedDepth / 8);
- }
-
- mBackBufferSize = bufferSize;
- mInitCheck = OK;
- }
-
- status_t initCheck() const { return mInitCheck; }
-
- uint32_t backBufferSize() const { return mBackBufferSize; }
-
- /**
- * Convert C2GraphicView to MediaImage2. Note that if not wrapped, the content
- * is not copied over in this function --- the caller should use
- * CopyGraphicView2MediaImage() function to do that explicitly.
- *
- * \param view[in] source C2GraphicView object.
- * \param alloc[in] allocator function for ABuffer.
- * \param mediaImage[out] destination MediaImage2 object.
- * \param buffer[out] new buffer object.
- * \param wrapped[out] whether we wrapped around existing map or
- * allocated a new buffer
- *
- * \return true if conversion succeeds,
- * false otherwise; all output params should be ignored.
- */
- sp<ABuffer> wrap() {
- MediaImage2 *mediaImage = getMediaImage();
- const C2PlanarLayout &layout = mView.layout();
- if (layout.numPlanes == 1) {
- const C2PlaneInfo &plane = layout.planes[0];
- ssize_t offset = plane.minOffset(mWidth, mHeight);
- mediaImage->mPlane[0].mOffset = -offset;
- mediaImage->mPlane[0].mColInc = plane.colInc;
- mediaImage->mPlane[0].mRowInc = plane.rowInc;
- mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
- mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
- return new ABuffer(
- const_cast<uint8_t *>(mView.data()[0] + offset),
- plane.maxOffset(mWidth, mHeight) - offset + 1);
- }
- const uint8_t *minPtr = mView.data()[0];
- const uint8_t *maxPtr = mView.data()[0];
- int32_t planeSize = 0;
- for (uint32_t i = 0; i < layout.numPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- ssize_t minOffset = plane.minOffset(mWidth, mHeight);
- ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
- if (minPtr > mView.data()[i] + minOffset) {
- minPtr = mView.data()[i] + minOffset;
- }
- if (maxPtr < mView.data()[i] + maxOffset) {
- maxPtr = mView.data()[i] + maxOffset;
- }
- planeSize += std::abs(plane.rowInc) * mHeight
- / plane.rowSampling / plane.colSampling * (mAllocatedDepth / 8);
- }
-
- if ((maxPtr - minPtr + 1) <= planeSize) {
- // FIXME: this is risky as reading/writing data out of bound results in
- // an undefined behavior.
- for (uint32_t i = 0; i < layout.numPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
- mediaImage->mPlane[i].mColInc = plane.colInc;
- mediaImage->mPlane[i].mRowInc = plane.rowInc;
- mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
- mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
- }
- return new ABuffer(const_cast<uint8_t *>(minPtr), maxPtr - minPtr + 1);
- }
-
- return nullptr;
- }
-
- bool setBackBuffer(const sp<ABuffer> &backBuffer) {
- if (backBuffer->capacity() < mBackBufferSize) {
- return false;
- }
- backBuffer->setRange(0, mBackBufferSize);
-
- const C2PlanarLayout &layout = mView.layout();
- MediaImage2 *mediaImage = getMediaImage();
- uint32_t offset = 0;
- // TODO: keep interleaved planes together
- for (uint32_t i = 0; i < layout.numPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- mediaImage->mPlane[i].mOffset = offset;
- mediaImage->mPlane[i].mColInc = mAllocatedDepth / 8;
- mediaImage->mPlane[i].mRowInc =
- mediaImage->mPlane[i].mColInc * mWidth / plane.colSampling;
- mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
- mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
- offset += mediaImage->mPlane[i].mRowInc * mHeight / plane.rowSampling;
- }
- mBackBuffer = backBuffer;
- return true;
- }
-
- /**
- * Copy C2GraphicView to MediaImage2. This function assumes that |mediaImage| is
- * an output from GraphicView2MediaImage(), so it mostly skips sanity check.
- *
- * \param view[in] source C2GraphicView object.
- * \param mediaImage[in] destination MediaImage2 object.
- * \param buffer[out] new buffer object.
- */
- void copy() {
- // TODO: more efficient copying --- e.g. one row at a time, copying
- // interleaved planes together, etc.
- const C2PlanarLayout &layout = mView.layout();
- MediaImage2 *mediaImage = getMediaImage();
- uint8_t *dst = mBackBuffer->base();
- for (uint32_t i = 0; i < layout.numPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- const uint8_t *src = mView.data()[i];
- int32_t planeW = mWidth / plane.colSampling;
- int32_t planeH = mHeight / plane.rowSampling;
- for (int32_t row = 0; row < planeH; ++row) {
- for(int32_t col = 0; col < planeW; ++col) {
- memcpy(dst, src, mAllocatedDepth / 8);
- dst += mediaImage->mPlane[i].mColInc;
- src += plane.colInc;
- }
- dst -= mediaImage->mPlane[i].mColInc * planeW;
- dst += mediaImage->mPlane[i].mRowInc;
- src -= plane.colInc * planeW;
- src += plane.rowInc;
- }
- }
- }
-
- const sp<ABuffer> &imageData() const { return mMediaImage; }
-
-private:
- status_t mInitCheck;
-
- const C2GraphicView mView;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mAllocatedDepth;
- uint32_t mBackBufferSize;
- sp<ABuffer> mMediaImage;
- std::function<sp<ABuffer>(size_t)> mAlloc;
-
- sp<ABuffer> mBackBuffer;
-
- MediaImage2 *getMediaImage() {
- return (MediaImage2 *)mMediaImage->base();
- }
-};
-
-} // namespace
-
-// GraphicBlockBuffer
-
-// static
-sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
- const sp<AMessage> &format,
- const std::shared_ptr<C2GraphicBlock> &block,
- std::function<sp<ABuffer>(size_t)> alloc) {
- C2GraphicView view(block->map().get());
- if (view.error() != C2_OK) {
- ALOGD("C2GraphicBlock::map failed: %d", view.error());
- return nullptr;
- }
- GraphicView2MediaImageConverter converter(view);
- if (converter.initCheck() != OK) {
- ALOGD("Converter init failed: %d", converter.initCheck());
- return nullptr;
- }
- bool wrapped = true;
- sp<ABuffer> buffer = converter.wrap();
- if (buffer == nullptr) {
- buffer = alloc(converter.backBufferSize());
- if (!converter.setBackBuffer(buffer)) {
- ALOGD("Converter failed to set back buffer");
- return nullptr;
- }
- wrapped = false;
- }
- return new GraphicBlockBuffer(
- format,
- buffer,
- std::move(view),
- block,
- converter.imageData(),
- wrapped);
-}
-
-GraphicBlockBuffer::GraphicBlockBuffer(
- const sp<AMessage> &format,
- const sp<ABuffer> &buffer,
- C2GraphicView &&view,
- const std::shared_ptr<C2GraphicBlock> &block,
- const sp<ABuffer> &imageData,
- bool wrapped)
- : Codec2Buffer(format, buffer),
- mView(view),
- mBlock(block),
- mImageData(imageData),
- mWrapped(wrapped) {
- meta()->setBuffer("image-data", imageData);
-}
-
-std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
- uint32_t width = mView.width();
- uint32_t height = mView.height();
- if (!mWrapped) {
- MediaImage2 *mediaImage = imageData();
- const C2PlanarLayout &layout = mView.layout();
- for (uint32_t i = 0; i < mediaImage->mNumPlanes; ++i) {
- const C2PlaneInfo &plane = layout.planes[i];
- int32_t planeW = width / plane.colSampling;
- int32_t planeH = height / plane.rowSampling;
- const uint8_t *src = base() + mediaImage->mPlane[i].mOffset;
- uint8_t *dst = mView.data()[i];
- for (int32_t row = 0; row < planeH; ++row) {
- for (int32_t col = 0; col < planeW; ++col) {
- memcpy(dst, src, mediaImage->mBitDepthAllocated / 8);
- src += mediaImage->mPlane[i].mColInc;
- dst += plane.colInc;
- }
- src -= mediaImage->mPlane[i].mColInc * planeW;
- dst -= plane.colInc * planeW;
- src += mediaImage->mPlane[i].mRowInc;
- dst += plane.rowInc;
- }
- }
- }
- return C2Buffer::CreateGraphicBuffer(
- mBlock->share(C2Rect(width, height), C2Fence()));
-}
-
-// ConstGraphicBlockBuffer
-
-// static
-sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
- const sp<AMessage> &format,
- const std::shared_ptr<C2Buffer> &buffer,
- std::function<sp<ABuffer>(size_t)> alloc) {
- if (!buffer
- || buffer->data().type() != C2BufferData::GRAPHIC
- || buffer->data().graphicBlocks().size() != 1u) {
- ALOGD("C2Buffer precond fail");
- return nullptr;
- }
- std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
- buffer->data().graphicBlocks()[0].map().get()));
- std::unique_ptr<const C2GraphicView> holder;
-
- GraphicView2MediaImageConverter converter(*view);
- if (converter.initCheck() != OK) {
- ALOGD("Converter init failed: %d", converter.initCheck());
- return nullptr;
- }
- bool wrapped = true;
- sp<ABuffer> aBuffer = converter.wrap();
- if (aBuffer == nullptr) {
- aBuffer = alloc(converter.backBufferSize());
- if (!converter.setBackBuffer(aBuffer)) {
- ALOGD("Converter failed to set back buffer");
- return nullptr;
- }
- wrapped = false;
- converter.copy();
- // We don't need the view.
- holder = std::move(view);
- }
- return new ConstGraphicBlockBuffer(
- format,
- aBuffer,
- std::move(view),
- buffer,
- converter.imageData(),
- wrapped);
-}
-
-// static
-sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
- const sp<AMessage> &format,
- std::function<sp<ABuffer>(size_t)> alloc) {
- int32_t width, height;
- if (!format->findInt32("width", &width)
- || !format->findInt32("height", &height)) {
- ALOGD("format had no width / height");
- return nullptr;
- }
- sp<ABuffer> aBuffer(alloc(width * height * 4));
- return new ConstGraphicBlockBuffer(
- format,
- aBuffer,
- nullptr,
- nullptr,
- nullptr,
- false);
-}
-
-ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
- const sp<AMessage> &format,
- const sp<ABuffer> &aBuffer,
- std::unique_ptr<const C2GraphicView> &&view,
- const std::shared_ptr<C2Buffer> &buffer,
- const sp<ABuffer> &imageData,
- bool wrapped)
- : Codec2Buffer(format, aBuffer),
- mView(std::move(view)),
- mBufferRef(buffer),
- mWrapped(wrapped) {
- if (imageData != nullptr) {
- meta()->setBuffer("image-data", imageData);
- }
-}
-
-std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
- mView.reset();
- return std::move(mBufferRef);
-}
-
-bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
- if (mWrapped || mBufferRef) {
- ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
- mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
- return false;
- }
- if (!buffer) {
- // Nothing to copy, so we can copy by doing nothing.
- return true;
- }
- if (buffer->data().type() != C2BufferData::GRAPHIC) {
- ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
- return false;
- }
- if (buffer->data().graphicBlocks().size() == 0) {
- return true;
- } else if (buffer->data().graphicBlocks().size() != 1u) {
- ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
- return false;
- }
- GraphicView2MediaImageConverter converter(
- buffer->data().graphicBlocks()[0].map().get());
- if (converter.initCheck() != OK) {
- ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
- return false;
- }
- if (converter.backBufferSize() > capacity()) {
- ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
- converter.backBufferSize(), capacity());
- return false;
- }
- return true;
-}
-
-bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
- if (!buffer || buffer->data().graphicBlocks().size() == 0) {
- setRange(0, 0);
- return true;
- }
- GraphicView2MediaImageConverter converter(
- buffer->data().graphicBlocks()[0].map().get());
- if (converter.initCheck() != OK) {
- ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
- return false;
- }
- sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
- if (!converter.setBackBuffer(aBuffer)) {
- ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
- return false;
- }
- converter.copy();
- meta()->setBuffer("image-data", converter.imageData());
- mBufferRef = buffer;
- return true;
-}
-
} // namespace android
diff --git a/media/libstagefright/C2OMXNode.cpp b/media/libstagefright/C2OMXNode.cpp
deleted file mode 100644
index 04faa28..0000000
--- a/media/libstagefright/C2OMXNode.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#ifdef __LP64__
-#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
-#endif
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "C2OMXNode"
-#include <log/log.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2BlockInternal.h>
-#include <C2Component.h>
-#include <C2PlatformSupport.h>
-
-#include <OMX_Component.h>
-#include <OMX_Index.h>
-#include <OMX_IndexExt.h>
-
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/MediaErrors.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-#include "include/C2OMXNode.h"
-
-namespace android {
-
-namespace {
-
-class Buffer2D : public C2Buffer {
-public:
- explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
-};
-
-} // namespace
-
-C2OMXNode::C2OMXNode(const std::shared_ptr<C2Component> &comp) : mComp(comp) {}
-
-status_t C2OMXNode::freeNode() {
- mComp.reset();
- return OK;
-}
-
-status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
- (void)cmd;
- (void)param;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::getParameter(OMX_INDEXTYPE index, void *params, size_t size) {
- status_t err = ERROR_UNSUPPORTED;
- switch ((uint32_t)index) {
- case OMX_IndexParamConsumerUsageBits: {
- // TODO: read from intf()
- OMX_U32 *usage = (OMX_U32 *)params;
- *usage = GRALLOC_USAGE_SW_READ_OFTEN;
- err = OK;
- break;
- }
- case OMX_IndexParamPortDefinition: {
- if (size < sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
- return BAD_VALUE;
- }
- OMX_PARAM_PORTDEFINITIONTYPE *pDef = (OMX_PARAM_PORTDEFINITIONTYPE *)params;
- // TODO: read these from intf()
- pDef->nBufferCountActual = 16;
- pDef->eDomain = OMX_PortDomainVideo;
- pDef->format.video.nFrameWidth = 1080;
- pDef->format.video.nFrameHeight = 1920;
- err = OK;
- break;
- }
- default:
- break;
- }
- return err;
-}
-
-status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
- (void)index;
- (void)params;
- (void)size;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::getConfig(OMX_INDEXTYPE index, void *config, size_t size) {
- (void)index;
- (void)config;
- (void)size;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::setConfig(OMX_INDEXTYPE index, const void *config, size_t size) {
- (void)index;
- (void)config;
- (void)size;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
- (void)portIndex;
- (void)mode;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::prepareForAdaptivePlayback(
- OMX_U32 portIndex, OMX_BOOL enable,
- OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
- (void)portIndex;
- (void)enable;
- (void)maxFrameWidth;
- (void)maxFrameHeight;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::configureVideoTunnelMode(
- OMX_U32 portIndex, OMX_BOOL tunneled,
- OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
- (void)portIndex;
- (void)tunneled;
- (void)audioHwSync;
- *sidebandHandle = nullptr;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage) {
- (void)portIndex;
- *usage = 0;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::setInputSurface(const sp<IOMXBufferSource> &bufferSource) {
- c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
- C2PlatformAllocatorStore::GRALLOC,
- &mAllocator);
- if (err != OK) {
- return UNKNOWN_ERROR;
- }
- mBufferSource = bufferSource;
- return OK;
-}
-
-status_t C2OMXNode::allocateSecureBuffer(
- OMX_U32 portIndex, size_t size, buffer_id *buffer,
- void **bufferData, sp<NativeHandle> *nativeHandle) {
- (void)portIndex;
- (void)size;
- (void)nativeHandle;
- *buffer = 0;
- *bufferData = nullptr;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::useBuffer(
- OMX_U32 portIndex, const OMXBuffer &omxBuf, buffer_id *buffer) {
- (void)portIndex;
- (void)omxBuf;
- *buffer = 0;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::freeBuffer(OMX_U32 portIndex, buffer_id buffer) {
- (void)portIndex;
- (void)buffer;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::fillBuffer(
- buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) {
- (void)buffer;
- (void)omxBuf;
- (void)fenceFd;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::emptyBuffer(
- buffer_id buffer, const OMXBuffer &omxBuf,
- OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
- // TODO: better fence handling
- if (fenceFd >= 0) {
- sp<Fence> fence = new Fence(fenceFd);
- fence->waitForever(LOG_TAG);
- }
- std::shared_ptr<C2Component> comp = mComp.lock();
- if (!comp) {
- return NO_INIT;
- }
-
- uint32_t c2Flags = 0;
- std::shared_ptr<C2GraphicBlock> block;
-
- C2Handle *handle = nullptr;
- if (omxBuf.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
- std::shared_ptr<C2GraphicAllocation> alloc;
- handle = WrapNativeCodec2GrallocHandle(
- native_handle_clone(omxBuf.mGraphicBuffer->handle),
- omxBuf.mGraphicBuffer->width,
- omxBuf.mGraphicBuffer->height,
- omxBuf.mGraphicBuffer->format,
- omxBuf.mGraphicBuffer->usage,
- omxBuf.mGraphicBuffer->stride);
- c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
- if (err != OK) {
- return UNKNOWN_ERROR;
- }
- block = _C2BlockFactory::CreateGraphicBlock(alloc);
- } else if (flags & OMX_BUFFERFLAG_EOS) {
- c2Flags = C2FrameData::FLAG_END_OF_STREAM;
- } else {
- return BAD_VALUE;
- }
-
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = (C2FrameData::flags_t)c2Flags;
- work->input.ordinal.timestamp = timestamp;
- work->input.ordinal.frameIndex = mFrameIndex++;
- work->input.buffers.clear();
- if (block) {
- std::shared_ptr<C2Buffer> c2Buffer(
- // TODO: fence
- new Buffer2D(block->share(
- C2Rect(block->width(), block->height()), ::C2Fence())),
- [handle, buffer, source = getSource()](C2Buffer *ptr) {
- delete ptr;
- native_handle_delete(handle);
- // TODO: fence
- (void)source->onInputBufferEmptied(buffer, -1);
- });
- work->input.buffers.push_back(c2Buffer);
- }
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- c2_status_t err = comp->queue_nb(&items);
- if (err != C2_OK) {
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2OMXNode::getExtensionIndex(
- const char *parameterName, OMX_INDEXTYPE *index) {
- (void)parameterName;
- *index = OMX_IndexMax;
- return ERROR_UNSUPPORTED;
-}
-
-status_t C2OMXNode::dispatchMessage(const omx_message& msg) {
- if (msg.type != omx_message::EVENT) {
- return ERROR_UNSUPPORTED;
- }
- if (msg.u.event_data.event != OMX_EventDataSpaceChanged) {
- return ERROR_UNSUPPORTED;
- }
- // TODO: fill intf() with info inside |msg|.
- return OK;
-}
-
-sp<IOMXBufferSource> C2OMXNode::getSource() {
- return mBufferSource;
-}
-
-} // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
deleted file mode 100644
index 0bdd808..0000000
--- a/media/libstagefright/CCodec.cpp
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- * Copyright (C) 2017 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 "CCodec"
-#include <cutils/properties.h>
-#include <utils/Log.h>
-
-#include <thread>
-
-#include <C2PlatformSupport.h>
-#include <C2V4l2Support.h>
-
-#include <android/IOMXBufferSource.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <gui/Surface.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
-#include <media/stagefright/BufferProducerWrapper.h>
-#include <media/stagefright/CCodec.h>
-#include <media/stagefright/PersistentSurface.h>
-
-#include "include/C2OMXNode.h"
-#include "include/CCodecBufferChannel.h"
-#include "include/InputSurfaceWrapper.h"
-
-namespace android {
-
-using namespace std::chrono_literals;
-using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
-
-namespace {
-
-class CCodecWatchdog : public AHandler {
-private:
- enum {
- kWhatRegister,
- kWhatWatch,
- };
- constexpr static int64_t kWatchIntervalUs = 3000000; // 3 secs
-
-public:
- static sp<CCodecWatchdog> getInstance() {
- Mutexed<sp<CCodecWatchdog>>::Locked instance(sInstance);
- if (*instance == nullptr) {
- *instance = new CCodecWatchdog;
- (*instance)->init();
- }
- return *instance;
- }
-
- ~CCodecWatchdog() = default;
-
- void registerCodec(CCodec *codec) {
- sp<AMessage> msg = new AMessage(kWhatRegister, this);
- msg->setPointer("codec", codec);
- msg->post();
- }
-
-protected:
- void onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatRegister: {
- void *ptr = nullptr;
- CHECK(msg->findPointer("codec", &ptr));
- Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs);
- codecs->emplace_back((CCodec *)ptr);
- break;
- }
-
- case kWhatWatch: {
- Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs);
- for (auto it = codecs->begin(); it != codecs->end(); ) {
- sp<CCodec> codec = it->promote();
- if (codec == nullptr) {
- it = codecs->erase(it);
- continue;
- }
- codec->initiateReleaseIfStuck();
- ++it;
- }
- msg->post(kWatchIntervalUs);
- break;
- }
-
- default: {
- TRESPASS("CCodecWatchdog: unrecognized message");
- }
- }
- }
-
-private:
- CCodecWatchdog() : mLooper(new ALooper) {}
-
- void init() {
- mLooper->setName("CCodecWatchdog");
- mLooper->registerHandler(this);
- mLooper->start();
- (new AMessage(kWhatWatch, this))->post(kWatchIntervalUs);
- }
-
- static Mutexed<sp<CCodecWatchdog>> sInstance;
-
- sp<ALooper> mLooper;
- Mutexed<std::list<wp<CCodec>>> mCodecs;
-};
-
-Mutexed<sp<CCodecWatchdog>> CCodecWatchdog::sInstance;
-
-class CCodecListener : public C2Component::Listener {
-public:
- explicit CCodecListener(const wp<CCodec> &codec) : mCodec(codec) {}
-
- virtual void onWorkDone_nb(
- std::weak_ptr<C2Component> component,
- std::list<std::unique_ptr<C2Work>> workItems) override {
- (void)component;
- sp<CCodec> codec(mCodec.promote());
- if (!codec) {
- return;
- }
- codec->onWorkDone(workItems);
- }
-
- virtual void onTripped_nb(
- std::weak_ptr<C2Component> component,
- std::vector<std::shared_ptr<C2SettingResult>> settingResult) override {
- // TODO
- (void)component;
- (void)settingResult;
- }
-
- virtual void onError_nb(std::weak_ptr<C2Component> component, uint32_t errorCode) override {
- // TODO
- (void)component;
- (void)errorCode;
- }
-
-private:
- wp<CCodec> mCodec;
-};
-
-class C2InputSurfaceWrapper : public InputSurfaceWrapper {
-public:
- explicit C2InputSurfaceWrapper(const sp<InputSurface> &surface) : mSurface(surface) {}
- ~C2InputSurfaceWrapper() override = default;
-
- status_t connect(const std::shared_ptr<C2Component> &comp) override {
- if (mConnection != nullptr) {
- return ALREADY_EXISTS;
- }
- mConnection = mSurface->connectToComponent(comp);
- return OK;
- }
-
- void disconnect() override {
- if (mConnection != nullptr) {
- mConnection->disconnect();
- mConnection.clear();
- }
- }
-
-private:
- sp<InputSurface> mSurface;
- sp<InputSurfaceConnection> mConnection;
-};
-
-class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
-public:
- explicit GraphicBufferSourceWrapper(const sp<IGraphicBufferSource> &source) : mSource(source) {}
- ~GraphicBufferSourceWrapper() override = default;
-
- status_t connect(const std::shared_ptr<C2Component> &comp) override {
- // TODO: proper color aspect & dataspace
- android_dataspace dataSpace = HAL_DATASPACE_BT709;
-
- mNode = new C2OMXNode(comp);
- mSource->configure(mNode, dataSpace);
-
- // TODO: configure according to intf().
-
- sp<IOMXBufferSource> source = mNode->getSource();
- if (source == nullptr) {
- return NO_INIT;
- }
- constexpr size_t kNumSlots = 16;
- for (size_t i = 0; i < kNumSlots; ++i) {
- source->onInputBufferAdded(i);
- }
- source->onOmxExecuting();
- return OK;
- }
-
- void disconnect() override {
- if (mNode == nullptr) {
- return;
- }
- sp<IOMXBufferSource> source = mNode->getSource();
- if (source == nullptr) {
- ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
- return;
- }
- source->onOmxIdle();
- source->onOmxLoaded();
- mNode.clear();
- }
-
-private:
- sp<IGraphicBufferSource> mSource;
- sp<C2OMXNode> mNode;
-};
-
-} // namespace
-
-CCodec::CCodec()
- : mChannel(new CCodecBufferChannel([this] (status_t err, enum ActionCode actionCode) {
- mCallback->onError(err, actionCode);
- })) {
- CCodecWatchdog::getInstance()->registerCodec(this);
-}
-
-CCodec::~CCodec() {
-}
-
-std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() {
- return mChannel;
-}
-
-status_t CCodec::tryAndReportOnError(std::function<status_t()> job) {
- status_t err = job();
- if (err != C2_OK) {
- mCallback->onError(err, ACTION_CODE_FATAL);
- }
- return err;
-}
-
-void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) {
- auto setAllocating = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != RELEASED) {
- return INVALID_OPERATION;
- }
- state->set(ALLOCATING);
- return OK;
- };
- if (tryAndReportOnError(setAllocating) != OK) {
- return;
- }
-
- AString componentName;
- if (!msg->findString("componentName", &componentName)) {
- // TODO: find componentName appropriate with the media type
- }
-
- sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this));
- allocMsg->setString("componentName", componentName);
- allocMsg->post();
-}
-
-void CCodec::allocate(const AString &componentName) {
- ALOGV("allocate(%s)", componentName.c_str());
- mListener.reset(new CCodecListener(this));
-
- std::shared_ptr<C2Component> comp;
- c2_status_t err = GetCodec2PlatformComponentStore()->createComponent(
- componentName.c_str(), &comp);
- static bool v4l2Enabled =
- property_get_bool("debug.stagefright.ccodec_v4l2", false);
- if (err != C2_OK && v4l2Enabled) {
- err = GetCodec2VDAComponentStore()->createComponent(
- componentName.c_str(), &comp);
- }
- if (err != C2_OK) {
- ALOGE("Failed Create component: %s", componentName.c_str());
- Mutexed<State>::Locked state(mState);
- state->set(RELEASED);
- state.unlock();
- mCallback->onError(err, ACTION_CODE_FATAL);
- state.lock();
- return;
- }
- ALOGV("Success Create component: %s", componentName.c_str());
- comp->setListener_vb(mListener, C2_MAY_BLOCK);
- mChannel->setComponent(comp);
- auto setAllocated = [this, comp] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != ALLOCATING) {
- state->set(RELEASED);
- return UNKNOWN_ERROR;
- }
- state->set(ALLOCATED);
- state->comp = comp;
- return OK;
- };
- if (tryAndReportOnError(setAllocated) != OK) {
- return;
- }
- mCallback->onComponentAllocated(comp->intf()->getName().c_str());
-}
-
-void CCodec::initiateConfigureComponent(const sp<AMessage> &format) {
- auto checkAllocated = [this] {
- Mutexed<State>::Locked state(mState);
- return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK;
- };
- if (tryAndReportOnError(checkAllocated) != OK) {
- return;
- }
-
- sp<AMessage> msg(new AMessage(kWhatConfigure, this));
- msg->setMessage("format", format);
- msg->post();
-}
-
-void CCodec::configure(const sp<AMessage> &msg) {
- std::shared_ptr<C2ComponentInterface> intf;
- auto checkAllocated = [this, &intf] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != ALLOCATED) {
- state->set(RELEASED);
- return UNKNOWN_ERROR;
- }
- intf = state->comp->intf();
- return OK;
- };
- if (tryAndReportOnError(checkAllocated) != OK) {
- return;
- }
-
- sp<AMessage> inputFormat(new AMessage);
- sp<AMessage> outputFormat(new AMessage);
- auto doConfig = [=] {
- AString mime;
- if (!msg->findString("mime", &mime)) {
- return BAD_VALUE;
- }
-
- int32_t encoder;
- if (!msg->findInt32("encoder", &encoder)) {
- encoder = false;
- }
-
- // TODO: read from intf()
- if ((!encoder) != (intf->getName().find("encoder") == std::string::npos)) {
- return UNKNOWN_ERROR;
- }
-
- sp<RefBase> obj;
- if (msg->findObject("native-window", &obj)) {
- sp<Surface> surface = static_cast<Surface *>(obj.get());
- setSurface(surface);
- }
-
- std::vector<std::unique_ptr<C2Param>> params;
- std::initializer_list<C2Param::Index> indices {
- C2PortMimeConfig::input::PARAM_TYPE,
- C2PortMimeConfig::output::PARAM_TYPE,
- };
- c2_status_t c2err = intf->query_vb(
- {},
- indices,
- C2_DONT_BLOCK,
- ¶ms);
- if (c2err != C2_OK) {
- ALOGE("Failed to query component interface: %d", c2err);
- return UNKNOWN_ERROR;
- }
- if (params.size() != indices.size()) {
- ALOGE("Component returns wrong number of params");
- return UNKNOWN_ERROR;
- }
- if (!params[0] || !params[1]) {
- ALOGE("Component returns null params");
- return UNKNOWN_ERROR;
- }
- inputFormat->setString("mime", ((C2PortMimeConfig *)params[0].get())->m.value);
- outputFormat->setString("mime", ((C2PortMimeConfig *)params[1].get())->m.value);
-
- // XXX: hack
- bool audio = mime.startsWithIgnoreCase("audio/");
- if (encoder) {
- if (audio) {
- inputFormat->setInt32("channel-count", 1);
- inputFormat->setInt32("sample-rate", 44100);
- outputFormat->setInt32("channel-count", 1);
- outputFormat->setInt32("sample-rate", 44100);
- } else {
- outputFormat->setInt32("width", 1080);
- outputFormat->setInt32("height", 1920);
- }
- } else {
- if (audio) {
- outputFormat->setInt32("channel-count", 2);
- outputFormat->setInt32("sample-rate", 44100);
- } else {
- int32_t tmp;
- if (msg->findInt32("width", &tmp)) {
- outputFormat->setInt32("width", tmp);
- }
- if (msg->findInt32("height", &tmp)) {
- outputFormat->setInt32("height", tmp);
- }
- }
- }
-
- // TODO
-
- return OK;
- };
- if (tryAndReportOnError(doConfig) != OK) {
- return;
- }
-
- {
- Mutexed<Formats>::Locked formats(mFormats);
- formats->inputFormat = inputFormat;
- formats->outputFormat = outputFormat;
- }
- mCallback->onComponentConfigured(inputFormat, outputFormat);
-}
-
-void CCodec::initiateCreateInputSurface() {
- status_t err = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != ALLOCATED) {
- return UNKNOWN_ERROR;
- }
- // TODO: read it from intf() properly.
- if (state->comp->intf()->getName().find("encoder") == std::string::npos) {
- return INVALID_OPERATION;
- }
- return OK;
- }();
- if (err != OK) {
- mCallback->onInputSurfaceCreationFailed(err);
- return;
- }
-
- (new AMessage(kWhatCreateInputSurface, this))->post();
-}
-
-void CCodec::createInputSurface() {
- // TODO: get this from codec process
- sp<InputSurface> surface(InputSurface::Create());
-
- // TODO: get proper error code.
- status_t err = (surface == nullptr) ? UNKNOWN_ERROR : OK;
- if (err != OK) {
- ALOGE("Failed to initialize input surface: %d", err);
- mCallback->onInputSurfaceCreationFailed(err);
- return;
- }
-
- err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface));
- if (err != OK) {
- ALOGE("Failed to set up input surface: %d", err);
- mCallback->onInputSurfaceCreationFailed(err);
- return;
- }
-
- sp<AMessage> inputFormat;
- sp<AMessage> outputFormat;
- {
- Mutexed<Formats>::Locked formats(mFormats);
- inputFormat = formats->inputFormat;
- outputFormat = formats->outputFormat;
- }
- mCallback->onInputSurfaceCreated(
- inputFormat,
- outputFormat,
- new BufferProducerWrapper(new H2BGraphicBufferProducer(surface)));
-}
-
-status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
- status_t err = mChannel->setInputSurface(surface);
- if (err != OK) {
- return err;
- }
-
- // TODO: configure |surface| with other settings.
- return OK;
-}
-
-void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
- sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
- msg->setObject("surface", surface);
- msg->post();
-}
-
-void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
- status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
- surface->getBufferSource()));
- if (err != OK) {
- ALOGE("Failed to set up input surface: %d", err);
- mCallback->onInputSurfaceDeclined(err);
- return;
- }
-
- sp<AMessage> inputFormat;
- sp<AMessage> outputFormat;
- {
- Mutexed<Formats>::Locked formats(mFormats);
- inputFormat = formats->inputFormat;
- outputFormat = formats->outputFormat;
- }
- mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
-}
-
-void CCodec::initiateStart() {
- auto setStarting = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != ALLOCATED) {
- return UNKNOWN_ERROR;
- }
- state->set(STARTING);
- return OK;
- };
- if (tryAndReportOnError(setStarting) != OK) {
- return;
- }
-
- (new AMessage(kWhatStart, this))->post();
-}
-
-void CCodec::start() {
- std::shared_ptr<C2Component> comp;
- auto checkStarting = [this, &comp] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != STARTING) {
- return UNKNOWN_ERROR;
- }
- comp = state->comp;
- return OK;
- };
- if (tryAndReportOnError(checkStarting) != OK) {
- return;
- }
-
- c2_status_t err = comp->start();
- if (err != C2_OK) {
- // TODO: convert err into status_t
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- return;
- }
- sp<AMessage> inputFormat;
- sp<AMessage> outputFormat;
- {
- Mutexed<Formats>::Locked formats(mFormats);
- inputFormat = formats->inputFormat;
- outputFormat = formats->outputFormat;
- }
- status_t err2 = mChannel->start(inputFormat, outputFormat);
- if (err2 != OK) {
- mCallback->onError(err2, ACTION_CODE_FATAL);
- return;
- }
-
- auto setRunning = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != STARTING) {
- return UNKNOWN_ERROR;
- }
- state->set(RUNNING);
- return OK;
- };
- if (tryAndReportOnError(setRunning) != OK) {
- return;
- }
- mCallback->onStartCompleted();
-}
-
-void CCodec::initiateShutdown(bool keepComponentAllocated) {
- if (keepComponentAllocated) {
- initiateStop();
- } else {
- initiateRelease();
- }
-}
-
-void CCodec::initiateStop() {
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() == ALLOCATED
- || state->get() == RELEASED
- || state->get() == STOPPING
- || state->get() == RELEASING) {
- // We're already stopped, released, or doing it right now.
- state.unlock();
- mCallback->onStopCompleted();
- state.lock();
- return;
- }
- state->set(STOPPING);
- }
-
- (new AMessage(kWhatStop, this))->post();
-}
-
-void CCodec::stop() {
- std::shared_ptr<C2Component> comp;
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() == RELEASING) {
- state.unlock();
- // We're already stopped or release is in progress.
- mCallback->onStopCompleted();
- state.lock();
- return;
- } else if (state->get() != STOPPING) {
- state.unlock();
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- state.lock();
- return;
- }
- comp = state->comp;
- }
- mChannel->stop();
- status_t err = comp->stop();
- if (err != C2_OK) {
- // TODO: convert err into status_t
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- }
-
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() == STOPPING) {
- state->set(ALLOCATED);
- }
- }
- mCallback->onStopCompleted();
-}
-
-void CCodec::initiateRelease(bool sendCallback /* = true */) {
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() == RELEASED || state->get() == RELEASING) {
- // We're already released or doing it right now.
- if (sendCallback) {
- state.unlock();
- mCallback->onReleaseCompleted();
- state.lock();
- }
- return;
- }
- if (state->get() == ALLOCATING) {
- state->set(RELEASING);
- // With the altered state allocate() would fail and clean up.
- if (sendCallback) {
- state.unlock();
- mCallback->onReleaseCompleted();
- state.lock();
- }
- return;
- }
- state->set(RELEASING);
- }
-
- std::thread([this, sendCallback] { release(sendCallback); }).detach();
-}
-
-void CCodec::release(bool sendCallback) {
- std::shared_ptr<C2Component> comp;
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() == RELEASED) {
- if (sendCallback) {
- state.unlock();
- mCallback->onReleaseCompleted();
- state.lock();
- }
- return;
- }
- comp = state->comp;
- }
- mChannel->stop();
- comp->release();
-
- {
- Mutexed<State>::Locked state(mState);
- state->set(RELEASED);
- state->comp.reset();
- }
- if (sendCallback) {
- mCallback->onReleaseCompleted();
- }
-}
-
-status_t CCodec::setSurface(const sp<Surface> &surface) {
- return mChannel->setSurface(surface);
-}
-
-void CCodec::signalFlush() {
- status_t err = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() == FLUSHED) {
- return ALREADY_EXISTS;
- }
- if (state->get() != RUNNING) {
- return UNKNOWN_ERROR;
- }
- state->set(FLUSHING);
- return OK;
- }();
- switch (err) {
- case ALREADY_EXISTS:
- mCallback->onFlushCompleted();
- return;
- case OK:
- break;
- default:
- mCallback->onError(err, ACTION_CODE_FATAL);
- return;
- }
-
- (new AMessage(kWhatFlush, this))->post();
-}
-
-void CCodec::flush() {
- std::shared_ptr<C2Component> comp;
- auto checkFlushing = [this, &comp] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != FLUSHING) {
- return UNKNOWN_ERROR;
- }
- comp = state->comp;
- return OK;
- };
- if (tryAndReportOnError(checkFlushing) != OK) {
- return;
- }
-
- mChannel->stop();
-
- std::list<std::unique_ptr<C2Work>> flushedWork;
- c2_status_t err = comp->flush_sm(C2Component::FLUSH_COMPONENT, &flushedWork);
- if (err != C2_OK) {
- // TODO: convert err into status_t
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- }
-
- mChannel->flush(flushedWork);
-
- {
- Mutexed<State>::Locked state(mState);
- state->set(FLUSHED);
- }
- mCallback->onFlushCompleted();
-}
-
-void CCodec::signalResume() {
- auto setResuming = [this] {
- Mutexed<State>::Locked state(mState);
- if (state->get() != FLUSHED) {
- return UNKNOWN_ERROR;
- }
- state->set(RESUMING);
- return OK;
- };
- if (tryAndReportOnError(setResuming) != OK) {
- return;
- }
-
- (void)mChannel->start(nullptr, nullptr);
-
- {
- Mutexed<State>::Locked state(mState);
- if (state->get() != RESUMING) {
- state.unlock();
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- state.lock();
- return;
- }
- state->set(RUNNING);
- }
-}
-
-void CCodec::signalSetParameters(const sp<AMessage> &msg) {
- // TODO
- (void) msg;
-}
-
-void CCodec::signalEndOfInputStream() {
- // TODO
- mCallback->onSignaledInputEOS(INVALID_OPERATION);
-}
-
-void CCodec::signalRequestIDRFrame() {
- // TODO
-}
-
-void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
- Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
- queue->splice(queue->end(), workItems);
- (new AMessage(kWhatWorkDone, this))->post();
-}
-
-void CCodec::onMessageReceived(const sp<AMessage> &msg) {
- TimePoint now = std::chrono::steady_clock::now();
- switch (msg->what()) {
- case kWhatAllocate: {
- // C2ComponentStore::createComponent() should return within 100ms.
- setDeadline(now + 150ms, "allocate");
- AString componentName;
- CHECK(msg->findString("componentName", &componentName));
- allocate(componentName);
- break;
- }
- case kWhatConfigure: {
- // C2Component::commit_sm() should return within 5ms.
- setDeadline(now + 50ms, "configure");
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
- configure(format);
- break;
- }
- case kWhatStart: {
- // C2Component::start() should return within 500ms.
- setDeadline(now + 550ms, "start");
- start();
- break;
- }
- case kWhatStop: {
- // C2Component::stop() should return within 500ms.
- setDeadline(now + 550ms, "stop");
- stop();
- break;
- }
- case kWhatFlush: {
- // C2Component::flush_sm() should return within 5ms.
- setDeadline(now + 50ms, "flush");
- flush();
- break;
- }
- case kWhatCreateInputSurface: {
- // Surface operations may be briefly blocking.
- setDeadline(now + 100ms, "createInputSurface");
- createInputSurface();
- break;
- }
- case kWhatSetInputSurface: {
- // Surface operations may be briefly blocking.
- setDeadline(now + 100ms, "setInputSurface");
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get()));
- setInputSurface(surface);
- break;
- }
- case kWhatWorkDone: {
- std::unique_ptr<C2Work> work;
- {
- Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
- if (queue->empty()) {
- break;
- }
- work.swap(queue->front());
- queue->pop_front();
- if (!queue->empty()) {
- (new AMessage(kWhatWorkDone, this))->post();
- }
- }
- mChannel->onWorkDone(work);
- break;
- }
- default: {
- ALOGE("unrecognized message");
- break;
- }
- }
- setDeadline(TimePoint::max(), "none");
-}
-
-void CCodec::setDeadline(const TimePoint &newDeadline, const char *name) {
- Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
- deadline->set(newDeadline, name);
-}
-
-void CCodec::initiateReleaseIfStuck() {
- std::string name;
- {
- Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
- if (deadline->get() >= std::chrono::steady_clock::now()) {
- // We're not stuck.
- return;
- }
- name = deadline->getName();
- }
-
- ALOGW("previous call to %s exceeded timeout", name.c_str());
- initiateRelease(false);
- mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
-}
-
-} // namespace android
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
deleted file mode 100644
index 65d637b..0000000
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ /dev/null
@@ -1,1402 +0,0 @@
-/*
- * Copyright 2017, 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 "CCodecBufferChannel"
-#include <utils/Log.h>
-
-#include <numeric>
-#include <thread>
-
-#include <C2AllocatorGralloc.h>
-#include <C2PlatformSupport.h>
-#include <C2BlockInternal.h>
-
-#include <android/hardware/cas/native/1.0/IDescrambler.h>
-#include <binder/MemoryDealer.h>
-#include <gui/Surface.h>
-#include <media/openmax/OMX_Core.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaCodec.h>
-#include <media/MediaCodecBuffer.h>
-#include <system/window.h>
-
-#include "include/CCodecBufferChannel.h"
-#include "include/Codec2Buffer.h"
-#include "include/SecureBuffer.h"
-#include "include/SharedMemoryBuffer.h"
-
-namespace android {
-
-using hardware::hidl_handle;
-using hardware::hidl_string;
-using hardware::hidl_vec;
-using namespace hardware::cas::V1_0;
-using namespace hardware::cas::native::V1_0;
-
-/**
- * Base class for representation of buffers at one port.
- */
-class CCodecBufferChannel::Buffers {
-public:
- Buffers() = default;
- virtual ~Buffers() = default;
-
- /**
- * Set format for MediaCodec-facing buffers.
- */
- void setFormat(const sp<AMessage> &format) {
- CHECK(format != nullptr);
- mFormat = format;
- }
-
- /**
- * Returns true if the buffers are operating under array mode.
- */
- virtual bool isArrayMode() const { return false; }
-
- /**
- * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
- * no-op.
- */
- virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
-
-protected:
- // Format to be used for creating MediaCodec-facing buffers.
- sp<AMessage> mFormat;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Buffers);
-};
-
-class CCodecBufferChannel::InputBuffers : public CCodecBufferChannel::Buffers {
-public:
- InputBuffers() = default;
- virtual ~InputBuffers() = default;
-
- /**
- * Set a block pool to obtain input memory blocks.
- */
- void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
-
- /**
- * Get a new MediaCodecBuffer for input and its corresponding index.
- * Returns false if no new buffer can be obtained at the moment.
- */
- virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
-
- /**
- * Release the buffer obtained from requestNewBuffer() and get the
- * associated C2Buffer object back. Returns empty shared_ptr if the
- * buffer is not on file.
- */
- virtual std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from requestNewBuffer() is valid.
- */
- virtual void flush() = 0;
-
- /**
- * Return array-backed version of input buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of requestNewBuffer().
- */
- virtual std::unique_ptr<InputBuffers> toArrayMode() = 0;
-
-protected:
- // Pool to obtain blocks for input buffers.
- std::shared_ptr<C2BlockPool> mPool;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
-};
-
-class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
-public:
- OutputBuffers() = default;
- virtual ~OutputBuffers() = default;
-
- /**
- * Register output C2Buffer from the component and obtain corresponding
- * index and MediaCodecBuffer object. Returns false if registration
- * fails.
- */
- virtual bool registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) = 0;
-
- /**
- * Register codec specific data as a buffer to be consistent with
- * MediaCodec behavior.
- */
- virtual bool registerCsd(
- const C2StreamCsdInfo::output * /* csd */,
- size_t * /* index */,
- sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
-
- /**
- * Release the buffer obtained from registerBuffer() and get the
- * associated C2Buffer object back. Returns empty shared_ptr if the
- * buffer is not on file.
- */
- virtual std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from registerBuffer() is valid.
- */
- virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
-
- /**
- * Return array-backed version of output buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of registerBuffer().
- */
- virtual std::unique_ptr<OutputBuffers> toArrayMode() = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
-};
-
-namespace {
-
-// TODO: get this info from component
-const static size_t kMinBufferArraySize = 16;
-const static size_t kLinearBufferSize = 524288;
-
-/**
- * Simple local buffer pool backed by std::vector.
- */
-class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
-public:
- /**
- * Create a new LocalBufferPool object.
- *
- * \param poolCapacity max total size of buffers managed by this pool.
- *
- * \return a newly created pool object.
- */
- static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity) {
- return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
- }
-
- /**
- * Return an ABuffer object whose size is at least |capacity|.
- *
- * \param capacity requested capacity
- * \return nullptr if the pool capacity is reached
- * an ABuffer object otherwise.
- */
- sp<ABuffer> newBuffer(size_t capacity) {
- Mutex::Autolock lock(mMutex);
- auto it = std::find_if(
- mPool.begin(), mPool.end(),
- [capacity](const std::vector<uint8_t> &vec) {
- return vec.capacity() >= capacity;
- });
- if (it != mPool.end()) {
- sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
- mPool.erase(it);
- return buffer;
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- while (!mPool.empty()) {
- mUsedSize -= mPool.back().capacity();
- mPool.pop_back();
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
- mUsedSize, capacity, mPoolCapacity);
- return nullptr;
- }
- }
- std::vector<uint8_t> vec(capacity);
- mUsedSize += vec.capacity();
- return new VectorBuffer(std::move(vec), shared_from_this());
- }
-
-private:
- /**
- * ABuffer backed by std::vector.
- */
- class VectorBuffer : public ::android::ABuffer {
- public:
- /**
- * Construct a VectorBuffer by taking the ownership of supplied vector.
- *
- * \param vec backing vector of the buffer. this object takes
- * ownership at construction.
- * \param pool a LocalBufferPool object to return the vector at
- * destruction.
- */
- VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
- : ABuffer(vec.data(), vec.capacity()),
- mVec(std::move(vec)),
- mPool(pool) {
- }
-
- ~VectorBuffer() override {
- std::shared_ptr<LocalBufferPool> pool = mPool.lock();
- if (pool) {
- // If pool is alive, return the vector back to the pool so that
- // it can be recycled.
- pool->returnVector(std::move(mVec));
- }
- }
-
- private:
- std::vector<uint8_t> mVec;
- std::weak_ptr<LocalBufferPool> mPool;
- };
-
- Mutex mMutex;
- size_t mPoolCapacity;
- size_t mUsedSize;
- std::list<std::vector<uint8_t>> mPool;
-
- /**
- * Private constructor to prevent constructing non-managed LocalBufferPool.
- */
- explicit LocalBufferPool(size_t poolCapacity)
- : mPoolCapacity(poolCapacity), mUsedSize(0) {
- }
-
- /**
- * Take back the ownership of vec from the destructed VectorBuffer and put
- * it in front of the pool.
- */
- void returnVector(std::vector<uint8_t> &&vec) {
- Mutex::Autolock lock(mMutex);
- mPool.push_front(std::move(vec));
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
-};
-
-sp<LinearBlockBuffer> AllocateLinearBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const sp<AMessage> &format,
- size_t size,
- const C2MemoryUsage &usage) {
- std::shared_ptr<C2LinearBlock> block;
-
- c2_status_t err = pool->fetchLinearBlock(size, usage, &block);
- if (err != C2_OK) {
- return nullptr;
- }
-
- return LinearBlockBuffer::Allocate(format, block);
-}
-
-sp<GraphicBlockBuffer> AllocateGraphicBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const sp<AMessage> &format,
- uint32_t pixelFormat,
- const C2MemoryUsage &usage,
- const std::shared_ptr<LocalBufferPool> &localBufferPool) {
- int32_t width, height;
- if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
- ALOGD("format lacks width or height");
- return nullptr;
- }
-
- std::shared_ptr<C2GraphicBlock> block;
- c2_status_t err = pool->fetchGraphicBlock(
- width, height, pixelFormat, usage, &block);
- if (err != C2_OK) {
- ALOGD("fetch graphic block failed: %d", err);
- return nullptr;
- }
-
- return GraphicBlockBuffer::Allocate(
- format,
- block,
- [localBufferPool](size_t capacity) {
- return localBufferPool->newBuffer(capacity);
- });
-}
-
-class BuffersArrayImpl;
-
-/**
- * Flexible buffer slots implementation.
- */
-class FlexBuffersImpl {
-public:
- FlexBuffersImpl() = default;
-
- /**
- * Assign an empty slot for a buffer and return the index. If there's no
- * empty slot, just add one at the end and return it.
- *
- * \param buffer[in] a new buffer to assign a slot.
- * \return index of the assigned slot.
- */
- size_t assignSlot(const sp<Codec2Buffer> &buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer.promote() == nullptr
- && mBuffers[i].compBuffer.expired()) {
- mBuffers[i].clientBuffer = buffer;
- return i;
- }
- }
- mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
- return mBuffers.size() - 1;
- }
-
- /**
- * Release the slot from the client, and get the C2Buffer object back from
- * the previously assigned buffer. Note that the slot is not completely free
- * until the returned C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously assigned a slot.
- * \return C2Buffer object from |buffer|.
- */
- std::shared_ptr<C2Buffer> releaseSlot(const sp<MediaCodecBuffer> &buffer) {
- sp<Codec2Buffer> c2Buffer;
- size_t index = mBuffers.size();
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer.promote() == buffer) {
- c2Buffer = mBuffers[i].clientBuffer.promote();
- index = i;
- break;
- }
- }
- if (c2Buffer == nullptr) {
- ALOGD("No matching buffer found");
- return nullptr;
- }
- std::shared_ptr<C2Buffer> result = c2Buffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- return result;
- }
-
-private:
- friend class BuffersArrayImpl;
-
- struct Entry {
- wp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- };
- std::vector<Entry> mBuffers;
-};
-
-/**
- * Static buffer slots implementation based on a fixed-size array.
- */
-class BuffersArrayImpl {
-public:
- /**
- * Initialize buffer array from the original |impl|. The buffers known by
- * the client is preserved, and the empty slots are populated so that the
- * array size is at least |minSize|.
- *
- * \param impl[in] FlexBuffersImpl object used so far.
- * \param minSize[in] minimum size of the buffer array.
- * \param allocate[in] function to allocate a client buffer for an empty slot.
- */
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
- sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer.promote();
- bool ownedByClient = (clientBuffer != nullptr);
- if (!ownedByClient) {
- clientBuffer = allocate();
- }
- mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
- }
- for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
- mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
- }
- }
-
- /**
- * Grab a buffer from the underlying array which matches the criteria.
- *
- * \param index[out] index of the slot.
- * \param buffer[out] the matching buffer.
- * \param match[in] a function to test whether the buffer matches the
- * criteria or not.
- * \return OK if successful,
- * NO_MEMORY if there's no available slot meets the criteria.
- */
- status_t grabBuffer(
- size_t *index,
- sp<Codec2Buffer> *buffer,
- std::function<bool(const sp<Codec2Buffer> &)> match =
- [](const sp<Codec2Buffer> &) { return true; }) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()
- && match(mBuffers[i].clientBuffer)) {
- mBuffers[i].ownedByClient = true;
- *buffer = mBuffers[i].clientBuffer;
- (*buffer)->meta()->clear();
- (*buffer)->setRange(0, (*buffer)->capacity());
- *index = i;
- return OK;
- }
- }
- return NO_MEMORY;
- }
-
- /**
- * Return the buffer from the client, and get the C2Buffer object back from
- * the buffer. Note that the slot is not completely free until the returned
- * C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously grabbed.
- * \return C2Buffer object from |buffer|.
- */
- std::shared_ptr<C2Buffer> returnBuffer(const sp<MediaCodecBuffer> &buffer) {
- sp<Codec2Buffer> c2Buffer;
- size_t index = mBuffers.size();
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer == buffer) {
- if (!mBuffers[i].ownedByClient) {
- ALOGD("Client returned a buffer it does not own according to our record: %zu", i);
- }
- c2Buffer = mBuffers[i].clientBuffer;
- mBuffers[i].ownedByClient = false;
- index = i;
- break;
- }
- }
- if (c2Buffer == nullptr) {
- ALOGD("No matching buffer found");
- return nullptr;
- }
- std::shared_ptr<C2Buffer> result = c2Buffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- return result;
- }
-
- /**
- * Populate |array| with the underlying buffer array.
- *
- * \param array[out] an array to be filled with the underlying buffer array.
- */
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const {
- array->clear();
- for (const Entry &entry : mBuffers) {
- array->push(entry.clientBuffer);
- }
- }
-
- /**
- * The client abandoned all known buffers, so reclaim the ownership.
- */
- void flush() {
- for (Entry &entry : mBuffers) {
- entry.ownedByClient = false;
- }
- }
-
-private:
- struct Entry {
- const sp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- bool ownedByClient;
- };
- std::vector<Entry> mBuffers;
-};
-
-class InputBuffersArray : public CCodecBufferChannel::InputBuffers {
-public:
- InputBuffersArray() = default;
- ~InputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final {
- return nullptr;
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(index, &c2Buffer);
- if (err == OK) {
- c2Buffer->setFormat(mFormat);
- *buffer = c2Buffer;
- return true;
- }
- return false;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) override {
- return mImpl.returnBuffer(buffer);
- }
-
- void flush() override {
- mImpl.flush();
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class LinearInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- using CCodecBufferChannel::InputBuffers::InputBuffers;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- // TODO: proper max input size
- // TODO: read usage from intf
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- sp<LinearBlockBuffer> newBuffer = AllocateLinearBuffer(
- mPool, mFormat, kLinearBufferSize, usage);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) override {
- return mImpl.releaseSlot(buffer);
- }
-
- void flush() override {
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final {
- std::unique_ptr<InputBuffersArray> array(new InputBuffersArray);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- kMinBufferArraySize,
- [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- return AllocateLinearBuffer(pool, format, kLinearBufferSize, usage);
- });
- return std::move(array);
- }
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- GraphicInputBuffers() : mLocalBufferPool(LocalBufferPool::Create(1920 * 1080 * 16)) {}
- ~GraphicInputBuffers() override = default;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- // TODO: proper max input size
- // TODO: read usage from intf
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
- mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) override {
- return mImpl.releaseSlot(buffer);
- }
-
- void flush() override {
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final {
- std::unique_ptr<InputBuffersArray> array(new InputBuffersArray);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- kMinBufferArraySize,
- [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- return AllocateGraphicBuffer(
- pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
- });
- return std::move(array);
- }
-
-private:
- FlexBuffersImpl mImpl;
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
-
-class DummyInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- DummyInputBuffers() = default;
-
- bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
- return false;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &) override {
- return nullptr;
- }
-
- void flush() override {
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final {
- return nullptr;
- }
-
- bool isArrayMode() const final { return true; }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- array->clear();
- }
-};
-
-class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
-public:
- OutputBuffersArray() = default;
- ~OutputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() final {
- return nullptr;
- }
-
- bool registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [buffer](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->canCopy(buffer);
- });
- if (err != OK) {
- ALOGD("grabBuffer failed: %d", err);
- return false;
- }
- c2Buffer->setFormat(mFormat);
- if (!c2Buffer->copy(buffer)) {
- ALOGD("copy buffer failed");
- return false;
- }
- *clientBuffer = c2Buffer;
- return true;
- }
-
- bool registerCsd(
- const C2StreamCsdInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [csd](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->base() != nullptr
- && clientBuffer->capacity() >= csd->flexCount();
- });
- if (err != OK) {
- return false;
- }
- // TODO: proper format update
- sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy(csd->m.value, csd->flexCount());
- mFormat = mFormat->dup();
- mFormat->setBuffer("csd-0", csdBuffer);
-
- memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
- c2Buffer->setRange(0, csd->flexCount());
- c2Buffer->setFormat(mFormat);
- *clientBuffer = c2Buffer;
- return true;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) final {
- return mImpl.returnBuffer(buffer);
- }
-
- void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void) flushedWork;
- mImpl.flush();
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers {
-public:
- using CCodecBufferChannel::OutputBuffers::OutputBuffers;
-
- bool registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) override {
- sp<Codec2Buffer> newBuffer = wrap(buffer);
- newBuffer->setFormat(mFormat);
- *index = mImpl.assignSlot(newBuffer);
- *clientBuffer = newBuffer;
- return true;
- }
-
- bool registerCsd(
- const C2StreamCsdInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- // TODO: proper format update
- sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy(csd->m.value, csd->flexCount());
- mFormat = mFormat->dup();
- mFormat->setBuffer("csd-0", csdBuffer);
-
- sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(mFormat, csdBuffer);
- *index = mImpl.assignSlot(newBuffer);
- *clientBuffer = newBuffer;
- return true;
- }
-
- std::shared_ptr<C2Buffer> releaseBuffer(
- const sp<MediaCodecBuffer> &buffer) override {
- return mImpl.releaseSlot(buffer);
- }
-
- void flush(
- const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void) flushedWork;
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
- std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- kMinBufferArraySize,
- [this]() { return allocateArrayBuffer(); });
- return std::move(array);
- }
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers.
- *
- * \param buffer C2Buffer object to wrap.
- *
- * \return appropriate Codec2Buffer object to wrap |buffer|.
- */
- virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers, to be
- * used as an empty array buffer.
- *
- * \return appropriate Codec2Buffer object which can copy() from C2Buffers.
- */
- virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class LinearOutputBuffers : public FlexOutputBuffers {
-public:
- using FlexOutputBuffers::FlexOutputBuffers;
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- if (buffer == nullptr) {
- return new DummyContainerBuffer(mFormat, buffer);
- }
- if (buffer->data().type() != C2BufferData::LINEAR) {
- // We expect linear output buffers from the component.
- return nullptr;
- }
- if (buffer->data().linearBlocks().size() != 1u) {
- // We expect one and only one linear block from the component.
- return nullptr;
- }
- return ConstLinearBlockBuffer::Allocate(mFormat, buffer);
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- // TODO: proper max output size
- return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
- }
-};
-
-class GraphicOutputBuffers : public FlexOutputBuffers {
-public:
- using FlexOutputBuffers::FlexOutputBuffers;
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- return new DummyContainerBuffer(mFormat, buffer);
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return new DummyContainerBuffer(mFormat);
- }
-};
-
-class RawGraphicOutputBuffers : public FlexOutputBuffers {
-public:
- RawGraphicOutputBuffers()
- : mLocalBufferPool(LocalBufferPool::Create(1920 * 1080 * 16)) {
- }
- ~RawGraphicOutputBuffers() override = default;
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- return ConstGraphicBlockBuffer::Allocate(
- mFormat,
- buffer,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return ConstGraphicBlockBuffer::AllocateEmpty(
- mFormat,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
-
-private:
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
-
-} // namespace
-
-CCodecBufferChannel::QueueGuard::QueueGuard(
- CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
- std::unique_lock<std::mutex> l(mSync.mMutex);
- // At this point it's guaranteed that mSync is not under state transition,
- // as we are holding its mutex.
- if (mSync.mCount == -1) {
- mRunning = false;
- } else {
- ++mSync.mCount;
- mRunning = true;
- }
-}
-
-CCodecBufferChannel::QueueGuard::~QueueGuard() {
- if (mRunning) {
- // We are not holding mutex at this point so that QueueSync::stop() can
- // keep holding the lock until mCount reaches zero.
- --mSync.mCount;
- }
-}
-
-void CCodecBufferChannel::QueueSync::start() {
- std::unique_lock<std::mutex> l(mMutex);
- // If stopped, it goes to running state; otherwise no-op.
- int32_t expected = -1;
- (void)mCount.compare_exchange_strong(expected, 0);
-}
-
-void CCodecBufferChannel::QueueSync::stop() {
- std::unique_lock<std::mutex> l(mMutex);
- if (mCount == -1) {
- // no-op
- return;
- }
- // Holding mutex here blocks creation of additional QueueGuard objects, so
- // mCount can only decrement. In other words, threads that acquired the lock
- // are allowed to finish execution but additional threads trying to acquire
- // the lock at this point will block, and then get QueueGuard at STOPPED
- // state.
- int32_t expected = 0;
- while (!mCount.compare_exchange_weak(expected, -1)) {
- std::this_thread::yield();
- }
-}
-
-CCodecBufferChannel::CCodecBufferChannel(
- const std::function<void(status_t, enum ActionCode)> &onError)
- : mOnError(onError),
- mFrameIndex(0u),
- mFirstValidFrameIndex(0u) {
-}
-
-CCodecBufferChannel::~CCodecBufferChannel() {
- if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
- mCrypto->unsetHeap(mHeapSeqNum);
- }
-}
-
-void CCodecBufferChannel::setComponent(const std::shared_ptr<C2Component> &component) {
- mComponent = component;
-}
-
-status_t CCodecBufferChannel::setInputSurface(
- const std::shared_ptr<InputSurfaceWrapper> &surface) {
- ALOGV("setInputSurface");
- mInputSurface = surface;
- return OK;
-}
-
-status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
- QueueGuard guard(mSync);
- if (!guard.isRunning()) {
- ALOGW("No more buffers should be queued at current state.");
- return -ENOSYS;
- }
-
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- int32_t flags = 0;
- int32_t tmp = 0;
- if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("input EOS");
- }
- if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
- flags |= C2FrameData::FLAG_CODEC_CONFIG;
- }
- ALOGV("queueInputBuffer: buffer->size() = %zu", buffer->size());
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = (C2FrameData::flags_t)flags;
- work->input.ordinal.timestamp = timeUs;
- work->input.ordinal.frameIndex = mFrameIndex++;
- work->input.buffers.clear();
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- work->input.buffers.push_back((*buffers)->releaseBuffer(buffer));
- }
- // TODO: fill info's
-
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
-
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
- return mComponent->queue_nb(&items);
-}
-
-status_t CCodecBufferChannel::queueSecureInputBuffer(
- const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
- const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- AString *errorDetailMsg) {
- // TODO
- (void) buffer;
- (void) secure;
- (void) key;
- (void) iv;
- (void) mode;
- (void) pattern;
- (void) subSamples;
- (void) numSubSamples;
- (void) errorDetailMsg;
- return -ENOSYS;
-}
-
-void CCodecBufferChannel::feedInputBufferIfAvailable() {
- sp<MediaCodecBuffer> inBuffer;
- size_t index;
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- if (!(*buffers)->requestNewBuffer(&index, &inBuffer)) {
- ALOGV("no new buffer available");
- inBuffer = nullptr;
- return;
- }
- }
- ALOGV("new input index = %zu", index);
- mCallback->onInputBufferAvailable(index, inBuffer);
-}
-
-status_t CCodecBufferChannel::renderOutputBuffer(
- const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
- ALOGV("renderOutputBuffer");
- feedInputBufferIfAvailable();
-
- std::shared_ptr<C2Buffer> c2Buffer;
- {
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
- c2Buffer = (*buffers)->releaseBuffer(buffer);
- }
-
- Mutexed<sp<Surface>>::Locked surface(mSurface);
- if (*surface == nullptr) {
- ALOGE("no surface");
- return OK;
- }
-
- std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
- if (blocks.size() != 1u) {
- ALOGE("# of graphic blocks expected to be 1, but %zu", blocks.size());
- return UNKNOWN_ERROR;
- }
-
- native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(blocks.front().handle());
- sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
- grallocHandle,
- GraphicBuffer::CLONE_HANDLE,
- blocks.front().width(),
- blocks.front().height(),
- HAL_PIXEL_FORMAT_YV12,
- // TODO
- 1,
- (uint64_t)GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- // TODO
- blocks.front().width()));
- native_handle_delete(grallocHandle);
-
- status_t result = (*surface)->attachBuffer(graphicBuffer.get());
- if (result != OK) {
- ALOGE("attachBuffer failed: %d", result);
- return result;
- }
-
- // TODO: read and set crop
-
- result = native_window_set_buffers_timestamp((*surface).get(), timestampNs);
- ALOGW_IF(result != OK, "failed to set buffer timestamp: %d", result);
-
- // TODO: fix after C2Fence implementation
-#if 0
- const C2Fence &fence = blocks.front().fence();
- result = ((ANativeWindow *)(*surface).get())->queueBuffer(
- (*surface).get(), graphicBuffer.get(), fence.valid() ? fence.fd() : -1);
-#else
- result = ((ANativeWindow *)(*surface).get())->queueBuffer(
- (*surface).get(), graphicBuffer.get(), -1);
-#endif
- if (result != OK) {
- ALOGE("queueBuffer failed: %d", result);
- return result;
- }
-
- return OK;
-}
-
-status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
- ALOGV("discardBuffer: %p", buffer.get());
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- (void)(*buffers)->releaseBuffer(buffer);
- }
- {
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
- if((*buffers)->releaseBuffer(buffer)) {
- buffers.unlock();
- feedInputBufferIfAvailable();
- buffers.lock();
- }
- }
- return OK;
-}
-
-void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- array->clear();
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-
- if (!(*buffers)->isArrayMode()) {
- *buffers = (*buffers)->toArrayMode();
- }
-
- (*buffers)->getArray(array);
-}
-
-void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- array->clear();
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
-
- if (!(*buffers)->isArrayMode()) {
- *buffers = (*buffers)->toArrayMode();
- }
-
- (*buffers)->getArray(array);
-}
-
-status_t CCodecBufferChannel::start(
- const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
- C2StreamFormatConfig::input iStreamFormat(0u);
- C2StreamFormatConfig::output oStreamFormat(0u);
- c2_status_t err = mComponent->intf()->query_vb(
- { &iStreamFormat, &oStreamFormat },
- {},
- C2_DONT_BLOCK,
- nullptr);
- if (err != C2_OK) {
- return UNKNOWN_ERROR;
- }
-
- if (inputFormat != nullptr) {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-
- bool graphic = (iStreamFormat.value == C2FormatVideo);
- if (graphic) {
- if (mInputSurface) {
- buffers->reset(new DummyInputBuffers);
- } else {
- buffers->reset(new GraphicInputBuffers);
- }
- } else {
- buffers->reset(new LinearInputBuffers);
- }
- (*buffers)->setFormat(inputFormat);
-
- ALOGV("graphic = %s", graphic ? "true" : "false");
- std::shared_ptr<C2BlockPool> pool;
- if (graphic) {
- err = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, mComponent, &pool);
- } else {
- err = CreateCodec2BlockPool(C2PlatformAllocatorStore::ION,
- mComponent, &pool);
- }
- if (err == C2_OK) {
- (*buffers)->setPool(pool);
- } else {
- // TODO: error
- }
- }
-
- if (outputFormat != nullptr) {
- bool hasOutputSurface = false;
- {
- Mutexed<sp<Surface>>::Locked surface(mSurface);
- hasOutputSurface = (*surface != nullptr);
- }
-
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
-
- bool graphic = (oStreamFormat.value == C2FormatVideo);
- if (graphic) {
- if (hasOutputSurface) {
- buffers->reset(new GraphicOutputBuffers);
- } else {
- buffers->reset(new RawGraphicOutputBuffers);
- }
- } else {
- buffers->reset(new LinearOutputBuffers);
- }
- (*buffers)->setFormat(outputFormat);
- }
-
- mSync.start();
- if (mInputSurface == nullptr) {
- // TODO: use proper buffer depth instead of this random value
- for (size_t i = 0; i < kMinBufferArraySize; ++i) {
- size_t index;
- sp<MediaCodecBuffer> buffer;
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- if (!(*buffers)->requestNewBuffer(&index, &buffer)) {
- if (i == 0) {
- ALOGE("start: cannot allocate memory at all");
- return NO_MEMORY;
- } else {
- ALOGV("start: cannot allocate memory, only %zu buffers allocated", i);
- }
- break;
- }
- }
- mCallback->onInputBufferAvailable(index, buffer);
- }
- } else {
- (void)mInputSurface->connect(mComponent);
- }
- return OK;
-}
-
-void CCodecBufferChannel::stop() {
- mSync.stop();
- mFirstValidFrameIndex = mFrameIndex.load();
- if (mInputSurface != nullptr) {
- mInputSurface->disconnect();
- mInputSurface.reset();
- }
-}
-
-void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- (*buffers)->flush();
- }
- {
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
- (*buffers)->flush(flushedWork);
- }
-}
-
-void CCodecBufferChannel::onWorkDone(const std::unique_ptr<C2Work> &work) {
- if (work->result != C2_OK) {
- if (work->result == C2_NOT_FOUND) {
- // TODO: Define what flushed work's result is.
- ALOGD("flushed work; ignored.");
- return;
- }
- ALOGD("work failed to complete: %d", work->result);
- mOnError(work->result, ACTION_CODE_FATAL);
- return;
- }
-
- // NOTE: MediaCodec usage supposedly have only one worklet
- if (work->worklets.size() != 1u) {
- ALOGE("onWorkDone: incorrect number of worklets: %zu",
- work->worklets.size());
- mOnError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- return;
- }
-
- const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
- if ((worklet->output.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
- // Discard frames from previous generation.
- return;
- }
- std::shared_ptr<C2Buffer> buffer;
- // NOTE: MediaCodec usage supposedly have only one output stream.
- if (worklet->output.buffers.size() > 1u) {
- ALOGE("onWorkDone: incorrect number of output buffers: %zu",
- worklet->output.buffers.size());
- mOnError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- return;
- } else if (worklet->output.buffers.size() == 1u) {
- buffer = worklet->output.buffers[0];
- if (!buffer) {
- ALOGW("onWorkDone: nullptr found in buffers; ignored.");
- }
- }
-
- const C2StreamCsdInfo::output *csdInfo = nullptr;
- for (const std::unique_ptr<C2Param> &info : worklet->output.configUpdate) {
- if (info->coreIndex() == C2StreamCsdInfo::output::CORE_INDEX) {
- ALOGV("onWorkDone: csd found");
- csdInfo = static_cast<const C2StreamCsdInfo::output *>(info.get());
- }
- }
-
- int32_t flags = 0;
- if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
- flags |= MediaCodec::BUFFER_FLAG_EOS;
- ALOGV("onWorkDone: output EOS");
- }
-
- sp<MediaCodecBuffer> outBuffer;
- size_t index;
- if (csdInfo != nullptr) {
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
- if ((*buffers)->registerCsd(csdInfo, &index, &outBuffer)) {
- outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek());
- outBuffer->meta()->setInt32("flags", flags | MediaCodec::BUFFER_FLAG_CODECCONFIG);
- ALOGV("onWorkDone: csd index = %zu", index);
-
- buffers.unlock();
- mCallback->onOutputBufferAvailable(index, outBuffer);
- buffers.lock();
- } else {
- ALOGE("onWorkDone: unable to register csd");
- buffers.unlock();
- mOnError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- buffers.lock();
- return;
- }
- }
-
- if (!buffer && !flags) {
- ALOGV("onWorkDone: Not reporting output buffer");
- return;
- }
-
- if (buffer) {
- for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
- // TODO: properly translate these to metadata
- switch (info->coreIndex().coreIndex()) {
- case C2StreamPictureTypeMaskInfo::CORE_INDEX:
- if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2PictureTypeKeyFrame) {
- flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
- }
- break;
- default:
- break;
- }
- }
- }
-
- {
- Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
- if (!(*buffers)->registerBuffer(buffer, &index, &outBuffer)) {
- ALOGE("onWorkDone: unable to register output buffer");
- buffers.unlock();
- mOnError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
- buffers.lock();
- return;
- }
- }
-
- outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek());
- outBuffer->meta()->setInt32("flags", flags);
- ALOGV("onWorkDone: out buffer index = %zu", index);
- mCallback->onOutputBufferAvailable(index, outBuffer);
-}
-
-status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
- if (newSurface != nullptr) {
- newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- }
-
- Mutexed<sp<Surface>>::Locked surface(mSurface);
-// if (newSurface == nullptr) {
-// if (*surface != nullptr) {
-// ALOGW("cannot unset a surface");
-// return INVALID_OPERATION;
-// }
-// return OK;
-// }
-//
-// if (*surface == nullptr) {
-// ALOGW("component was not configured with a surface");
-// return INVALID_OPERATION;
-// }
-
- *surface = newSurface;
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/Codec2InfoBuilder.cpp b/media/libstagefright/Codec2InfoBuilder.cpp
deleted file mode 100644
index 7ce2ff1..0000000
--- a/media/libstagefright/Codec2InfoBuilder.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2InfoBuilder"
-#include <log/log.h>
-
-#include <C2Component.h>
-#include <C2PlatformSupport.h>
-#include <C2V4l2Support.h>
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-#include <media/stagefright/Codec2InfoBuilder.h>
-
-namespace android {
-
-using ConstTraitsPtr = std::shared_ptr<const C2Component::Traits>;
-
-status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
- // Obtain C2ComponentStore
- std::shared_ptr<C2ComponentStore> store = GetCodec2PlatformComponentStore();
- if (store == nullptr) {
- ALOGE("Cannot find a component store.");
- return NO_INIT;
- }
-
- std::vector<ConstTraitsPtr> traits = store->listComponents();
-
- if (property_get_bool("debug.stagefright.ccodec_v4l2", false)) {
- std::shared_ptr<C2ComponentStore> v4l2Store = GetCodec2VDAComponentStore();
- if (v4l2Store == nullptr) {
- ALOGD("Cannot find a V4L2 component store.");
- // non-fatal.
- } else {
- std::vector<ConstTraitsPtr> v4l2Traits = v4l2Store->listComponents();
- traits.insert(traits.end(), v4l2Traits.begin(), v4l2Traits.end());
- }
- }
-
- MediaCodecsXmlParser parser(
- MediaCodecsXmlParser::defaultSearchDirs,
- "media_codecs_c2.xml");
- if (parser.getParsingStatus() != OK) {
- ALOGD("XML parser no good");
- return OK;
- }
- for (const ConstTraitsPtr &trait : traits) {
- if (parser.getCodecMap().count(trait->name.c_str()) == 0) {
- ALOGD("%s not found in xml", trait->name.c_str());
- continue;
- }
- const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(trait->name);
- std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
- codecInfo->setName(trait->name.c_str());
- codecInfo->setOwner("dummy");
- // TODO: get this from trait->kind
- bool encoder = (trait->name.find("encoder") != std::string::npos);
- codecInfo->setEncoder(encoder);
- codecInfo->setRank(trait->rank);
- for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
- const std::string &mediaType = typeIt->first;
- const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
- std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- codecInfo->addMime(mediaType.c_str());
- for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
- std::string key, value;
- std::tie(key, value) = *attrIt;
- if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
- caps->addDetail(key.c_str(), std::stoi(value));
- } else {
- caps->addDetail(key.c_str(), value.c_str());
- }
- }
- // TODO: get this from intf().
- if (mediaType.find("video") != std::string::npos && !encoder) {
- caps->addColorFormat(0x7F420888); // COLOR_FormatYUV420Flexible
- }
- }
- }
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 9748a8b..3d0aad1 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -495,27 +495,27 @@
mGridRows = mGridCols = 1;
if (overrideMeta == NULL) {
// check if we're dealing with a tiled heif
- int32_t gridWidth, gridHeight, gridRows, gridCols;
- if (trackMeta()->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
- && trackMeta()->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0
+ int32_t tileWidth, tileHeight, gridRows, gridCols;
+ if (trackMeta()->findInt32(kKeyTileWidth, &tileWidth) && tileWidth > 0
+ && trackMeta()->findInt32(kKeyTileHeight, &tileHeight) && tileHeight > 0
&& trackMeta()->findInt32(kKeyGridRows, &gridRows) && gridRows > 0
&& trackMeta()->findInt32(kKeyGridCols, &gridCols) && gridCols > 0) {
int32_t width, height;
CHECK(trackMeta()->findInt32(kKeyWidth, &width));
CHECK(trackMeta()->findInt32(kKeyHeight, &height));
- if (width <= gridWidth * gridCols && height <= gridHeight * gridRows) {
- ALOGV("grid: %dx%d, size: %dx%d, picture size: %dx%d",
- gridCols, gridRows, gridWidth, gridHeight, width, height);
+ if (width <= tileWidth * gridCols && height <= tileHeight * gridRows) {
+ ALOGV("grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
+ gridCols, gridRows, tileWidth, tileHeight, width, height);
overrideMeta = new MetaData(*(trackMeta()));
- overrideMeta->setInt32(kKeyWidth, gridWidth);
- overrideMeta->setInt32(kKeyHeight, gridHeight);
+ overrideMeta->setInt32(kKeyWidth, tileWidth);
+ overrideMeta->setInt32(kKeyHeight, tileHeight);
mGridCols = gridCols;
mGridRows = gridRows;
} else {
- ALOGE("bad grid: %dx%d, size: %dx%d, picture size: %dx%d",
- gridCols, gridRows, gridWidth, gridHeight, width, height);
+ ALOGE("bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
+ gridCols, gridRows, tileWidth, tileHeight, width, height);
}
}
if (overrideMeta == NULL) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index cfbbcb2..a3261d7 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -358,7 +358,7 @@
Vector<uint16_t> mDimgRefs;
int32_t mIsPrimary;
int32_t mWidth, mHeight;
- int32_t mGridWidth, mGridHeight;
+ int32_t mTileWidth, mTileHeight;
int32_t mGridRows, mGridCols;
size_t mNumTiles, mTileIndex;
@@ -1376,15 +1376,12 @@
}
void MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) {
- const size_t kExtensionNALSearchRange = 64; // bytes to look for non-VCL NALUs
-
const uint8_t *dataStart = (const uint8_t *)buffer->data() + buffer->range_offset();
const uint8_t *currentNalStart = dataStart;
const uint8_t *nextNalStart;
const uint8_t *data = dataStart;
size_t nextNalSize;
- size_t searchSize = buffer->range_length() > kExtensionNALSearchRange ?
- kExtensionNALSearchRange : buffer->range_length();
+ size_t searchSize = buffer->range_length();
while (getNextNALUnit(&data, &searchSize, &nextNalStart,
&nextNalSize, true) == OK) {
@@ -1773,8 +1770,8 @@
mIsPrimary(0),
mWidth(0),
mHeight(0),
- mGridWidth(0),
- mGridHeight(0),
+ mTileWidth(0),
+ mTileHeight(0),
mGridRows(0),
mGridCols(0),
mNumTiles(1),
@@ -1805,13 +1802,13 @@
CHECK(mMeta->findInt32(kKeyWidth, &mWidth) && (mWidth > 0));
CHECK(mMeta->findInt32(kKeyHeight, &mHeight) && (mHeight > 0));
- int32_t gridWidth, gridHeight, gridRows, gridCols;
- if (mMeta->findInt32(kKeyGridWidth, &gridWidth) && (gridWidth > 0) &&
- mMeta->findInt32(kKeyGridHeight, &gridHeight) && (gridHeight > 0) &&
+ int32_t tileWidth, tileHeight, gridRows, gridCols;
+ if (mMeta->findInt32(kKeyTileWidth, &tileWidth) && (tileWidth > 0) &&
+ mMeta->findInt32(kKeyTileHeight, &tileHeight) && (tileHeight > 0) &&
mMeta->findInt32(kKeyGridRows, &gridRows) && (gridRows > 0) &&
mMeta->findInt32(kKeyGridCols, &gridCols) && (gridCols > 0)) {
- mGridWidth = gridWidth;
- mGridHeight = gridHeight;
+ mTileWidth = tileWidth;
+ mTileHeight = tileHeight;
mGridRows = gridRows;
mGridCols = gridCols;
mNumTiles = gridRows * gridCols;
@@ -1962,6 +1959,17 @@
return;
}
+ // Rotation angle in HEIF is CCW, framework angle is CW.
+ int32_t heifRotation = 0;
+ switch(mRotation) {
+ case 90: heifRotation = 3; break;
+ case 180: heifRotation = 2; break;
+ case 270: heifRotation = 1; break;
+ default: break; // don't set if invalid
+ }
+
+ bool hasGrid = (mNumTiles > 1);
+
if (mProperties.empty()) {
mProperties.push_back(mOwner->addProperty_l({
.type = FOURCC('h', 'v', 'c', 'C'),
@@ -1970,22 +1978,29 @@
mProperties.push_back(mOwner->addProperty_l({
.type = FOURCC('i', 's', 'p', 'e'),
- .width = (mNumTiles > 1) ? mGridWidth : mWidth,
- .height = (mNumTiles > 1) ? mGridHeight : mHeight,
+ .width = hasGrid ? mTileWidth : mWidth,
+ .height = hasGrid ? mTileHeight : mHeight,
}));
+
+ if (!hasGrid && heifRotation > 0) {
+ mProperties.push_back(mOwner->addProperty_l({
+ .type = FOURCC('i', 'r', 'o', 't'),
+ .rotation = heifRotation,
+ }));
+ }
}
uint16_t itemId = mOwner->addItem_l({
.itemType = "hvc1",
- .isPrimary = (mNumTiles > 1) ? false : (mIsPrimary != 0),
- .isHidden = (mNumTiles > 1),
+ .isPrimary = hasGrid ? false : (mIsPrimary != 0),
+ .isHidden = hasGrid,
.offset = (uint32_t)offset,
.size = (uint32_t)size,
.properties = mProperties,
});
mTileIndex++;
- if (mNumTiles > 1) {
+ if (hasGrid) {
mDimgRefs.push_back(itemId);
if (mTileIndex == mNumTiles) {
@@ -1995,6 +2010,12 @@
.width = mWidth,
.height = mHeight,
}));
+ if (heifRotation > 0) {
+ mProperties.push_back(mOwner->addProperty_l({
+ .type = FOURCC('i', 'r', 'o', 't'),
+ .rotation = heifRotation,
+ }));
+ }
mOwner->addItem_l({
.itemType = "grid",
.isPrimary = (mIsPrimary != 0),
@@ -2305,7 +2326,8 @@
mStartTimeRealUs = startTimeUs;
int32_t rotationDegrees;
- if (mIsVideo && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
+ if ((mIsVideo || mIsHeic) && params &&
+ params->findInt32(kKeyRotation, &rotationDegrees)) {
mRotation = rotationDegrees;
}
@@ -3430,16 +3452,36 @@
int32_t MPEG4Writer::Track::getMetaSizeIncrease() const {
CHECK(mIsHeic);
- return 20 // 1. 'ispe' property
- + (8 + mCodecSpecificDataSize) // 2. 'hvcC' property
- + (20 // 3. extra 'ispe'
- + (8 + 2 + 2 + mNumTiles * 2) // 4. 'dimg' ref
- + 12) // 5. ImageGrid in 'idat' (worst case)
- * (mNumTiles > 1) // - (3~5: applicable only if grid)
- + (16 // 6. increase to 'iloc'
- + 21 // 7. increase to 'iinf'
- + (3 + 2 * 2)) // 8. increase to 'ipma' (worst case)
- * (mNumTiles + 1); // - (6~8: are per-item)
+
+ int32_t grid = (mNumTiles > 1);
+
+ // Note that the rotation angle is in the file meta, and we don't have
+ // it until start, so here the calculation has to assume rotation.
+
+ // increase to ipco
+ int32_t increase = 20 * (grid + 1) // 'ispe' property
+ + (8 + mCodecSpecificDataSize) // 'hvcC' property
+ + 9; // 'irot' property (worst case)
+
+ // increase to iref and idat
+ if (grid) {
+ increase += (8 + 2 + 2 + mNumTiles * 2) // 'dimg' in iref
+ + 12; // ImageGrid in 'idat' (worst case)
+ }
+
+ // increase to iloc, iinf and ipma
+ increase += (16 // increase to 'iloc'
+ + 21 // increase to 'iinf'
+ + (3 + 2 * 2)) // increase to 'ipma' (worst case, 2 props x 2 bytes)
+ * (mNumTiles + grid);
+
+ // adjust to ipma:
+ // if rotation is present and only one tile, it could ref 3 properties
+ if (!grid) {
+ increase += 2;
+ }
+
+ return increase;
}
status_t MPEG4Writer::Track::checkCodecSpecificData() const {
@@ -4267,24 +4309,38 @@
numProperties = 32767;
}
for (size_t propIndex = 0; propIndex < numProperties; propIndex++) {
- if (mProperties[propIndex].type == FOURCC('h', 'v', 'c', 'C')) {
- beginBox("hvcC");
- sp<ABuffer> hvcc = mProperties[propIndex].hvcc;
- // Patch avcc's lengthSize field to match the number
- // of bytes we use to indicate the size of a nal unit.
- uint8_t *ptr = (uint8_t *)hvcc->data();
- ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1);
- write(hvcc->data(), hvcc->size());
- endBox();
- } else if (mProperties[propIndex].type == FOURCC('i', 's', 'p', 'e')) {
- beginBox("ispe");
- writeInt32(0); // Version = 0, Flags = 0
- writeInt32(mProperties[propIndex].width);
- writeInt32(mProperties[propIndex].height);
- endBox();
- } else {
- ALOGW("Skipping unrecognized property: type 0x%08x",
- mProperties[propIndex].type);
+ switch (mProperties[propIndex].type) {
+ case FOURCC('h', 'v', 'c', 'C'):
+ {
+ beginBox("hvcC");
+ sp<ABuffer> hvcc = mProperties[propIndex].hvcc;
+ // Patch avcc's lengthSize field to match the number
+ // of bytes we use to indicate the size of a nal unit.
+ uint8_t *ptr = (uint8_t *)hvcc->data();
+ ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1);
+ write(hvcc->data(), hvcc->size());
+ endBox();
+ break;
+ }
+ case FOURCC('i', 's', 'p', 'e'):
+ {
+ beginBox("ispe");
+ writeInt32(0); // Version = 0, Flags = 0
+ writeInt32(mProperties[propIndex].width);
+ writeInt32(mProperties[propIndex].height);
+ endBox();
+ break;
+ }
+ case FOURCC('i', 'r', 'o', 't'):
+ {
+ beginBox("irot");
+ writeInt8(mProperties[propIndex].rotation);
+ endBox();
+ break;
+ }
+ default:
+ ALOGW("Skipping unrecognized property: type 0x%08x",
+ mProperties[propIndex].type);
}
}
endBox();
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7d5c63a..5ad4c01 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -16,11 +16,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaCodec"
+#include <utils/Log.h>
+
#include <inttypes.h>
#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
+#include "StagefrightPluginLoader.h"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
@@ -45,7 +48,6 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/ACodec.h>
#include <media/stagefright/BufferProducerWrapper.h>
-#include <media/stagefright/CCodec.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
@@ -56,7 +58,6 @@
#include <media/stagefright/SurfaceUtils.h>
#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
-#include <utils/Log.h>
#include <utils/Singleton.h>
namespace android {
@@ -422,14 +423,12 @@
const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
uid_t uid) {
Vector<AString> matchingCodecs;
- Vector<AString> owners;
MediaCodecList::findMatchingCodecs(
mime.c_str(),
encoder,
0,
- &matchingCodecs,
- &owners);
+ &matchingCodecs);
if (err != NULL) {
*err = NAME_NOT_FOUND;
@@ -572,11 +571,15 @@
response->postReply(replyID);
}
+static CodecBase *CreateCCodec() {
+ return StagefrightPluginLoader::GetCCodecInstance()->createCodec();
+}
+
//static
sp<CodecBase> MediaCodec::GetCodecBase(const AString &name) {
static bool ccodecEnabled = property_get_bool("debug.stagefright.ccodec", false);
if (ccodecEnabled && name.startsWithIgnoreCase("c2.")) {
- return new CCodec;
+ return CreateCCodec();
} else if (name.startsWithIgnoreCase("omx.")) {
// at this time only ACodec specifies a mime type.
return new ACodec;
@@ -603,6 +606,8 @@
return NAME_NOT_FOUND;
}
+ mCodecInfo.clear();
+
bool secureCodec = false;
AString tmp = name;
if (tmp.endsWith(".secure")) {
@@ -614,17 +619,24 @@
mCodec = NULL; // remove the codec.
return NO_INIT; // if called from Java should raise IOException
}
- ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
- if (codecIdx >= 0) {
- const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
+ for (const AString &codecName : { name, tmp }) {
+ ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
+ if (codecIdx < 0) {
+ continue;
+ }
+ mCodecInfo = mcl->getCodecInfo(codecIdx);
Vector<AString> mimes;
- info->getSupportedMimes(&mimes);
+ mCodecInfo->getSupportedMimes(&mimes);
for (size_t i = 0; i < mimes.size(); i++) {
if (mimes[i].startsWith("video/")) {
mIsVideo = true;
break;
}
}
+ break;
+ }
+ if (mCodecInfo == nullptr) {
+ return NAME_NOT_FOUND;
}
if (mIsVideo) {
@@ -651,6 +663,9 @@
new BufferCallback(new AMessage(kWhatCodecNotify, this))));
sp<AMessage> msg = new AMessage(kWhatInit, this);
+ msg->setObject("codecInfo", mCodecInfo);
+ // name may be different from mCodecInfo->getCodecName() if we stripped
+ // ".secure"
msg->setString("name", name);
if (mAnalyticsItem != NULL) {
@@ -1205,6 +1220,22 @@
return OK;
}
+status_t MediaCodec::getCodecInfo(sp<MediaCodecInfo> *codecInfo) const {
+ sp<AMessage> msg = new AMessage(kWhatGetCodecInfo, this);
+
+ sp<AMessage> response;
+ status_t err;
+ if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
+ return err;
+ }
+
+ sp<RefBase> obj;
+ CHECK(response->findObject("codecInfo", &obj));
+ *codecInfo = static_cast<MediaCodecInfo *>(obj.get());
+
+ return OK;
+}
+
status_t MediaCodec::getMetrics(MediaAnalyticsItem * &reply) {
reply = NULL;
@@ -1972,11 +2003,14 @@
mReplyID = replyID;
setState(INITIALIZING);
+ sp<RefBase> codecInfo;
+ CHECK(msg->findObject("codecInfo", &codecInfo));
AString name;
CHECK(msg->findString("name", &name));
sp<AMessage> format = new AMessage;
- format->setString("componentName", name.c_str());
+ format->setObject("codecInfo", codecInfo);
+ format->setString("componentName", name);
mCodec->initiateAllocateComponent(format);
break;
@@ -2595,6 +2629,17 @@
break;
}
+ case kWhatGetCodecInfo:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ sp<AMessage> response = new AMessage;
+ response->setObject("codecInfo", mCodecInfo);
+ response->postReply(replyID);
+ break;
+ }
+
case kWhatSetParameters:
{
sp<AReplyToken> replyID;
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index f595646..cd091a6 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "MediaCodecListOverrides.h"
+#include "StagefrightPluginLoader.h"
#include <binder/IServiceManager.h>
@@ -29,7 +30,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/MediaDefs.h>
-#include <media/stagefright/Codec2InfoBuilder.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OmxInfoBuilder.h>
@@ -78,14 +78,25 @@
}
OmxInfoBuilder sOmxInfoBuilder;
-Codec2InfoBuilder sCodec2InfoBuilder;
-std::initializer_list<MediaCodecListBuilderBase *> GetBuilders() {
- if (property_get_bool("debug.stagefright.ccodec", false)) {
- return {&sOmxInfoBuilder, &sCodec2InfoBuilder};
- } else {
- return {&sOmxInfoBuilder};
+Mutex sCodec2InfoBuilderMutex;
+std::unique_ptr<MediaCodecListBuilderBase> sCodec2InfoBuilder;
+
+MediaCodecListBuilderBase *GetCodec2InfoBuilder() {
+ Mutex::Autolock _l(sCodec2InfoBuilderMutex);
+ if (!sCodec2InfoBuilder) {
+ sCodec2InfoBuilder.reset(
+ StagefrightPluginLoader::GetCCodecInstance()->createBuilder());
}
+ return sCodec2InfoBuilder.get();
+}
+
+std::vector<MediaCodecListBuilderBase *> GetBuilders() {
+ std::vector<MediaCodecListBuilderBase *> builders {&sOmxInfoBuilder};
+ if (property_get_bool("debug.stagefright.ccodec", false)) {
+ builders.push_back(GetCodec2InfoBuilder());
+ }
+ return builders;
}
} // unnamed namespace
@@ -179,16 +190,22 @@
return sRemoteList;
}
-MediaCodecList::MediaCodecList(std::initializer_list<MediaCodecListBuilderBase*> builders) {
+MediaCodecList::MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders) {
mGlobalSettings = new AMessage();
mCodecInfos.clear();
- MediaCodecListWriter writer(this);
+ MediaCodecListWriter writer;
for (MediaCodecListBuilderBase *builder : builders) {
+ if (builder == nullptr) {
+ ALOGD("ignored a null builder");
+ continue;
+ }
mInitCheck = builder->buildMediaCodecList(&writer);
if (mInitCheck != OK) {
break;
}
}
+ writer.writeGlobalSettings(mGlobalSettings);
+ writer.writeCodecInfos(&mCodecInfos);
std::stable_sort(
mCodecInfos.begin(),
mCodecInfos.end(),
@@ -210,23 +227,6 @@
return mInitCheck;
}
-MediaCodecListWriter::MediaCodecListWriter(MediaCodecList* list) :
- mList(list) {
-}
-
-void MediaCodecListWriter::addGlobalSetting(
- const char* key, const char* value) {
- mList->mGlobalSettings->setString(key, value);
-}
-
-std::unique_ptr<MediaCodecInfoWriter>
- MediaCodecListWriter::addMediaCodecInfo() {
- sp<MediaCodecInfo> info = new MediaCodecInfo();
- mList->mCodecInfos.push_back(info);
- return std::unique_ptr<MediaCodecInfoWriter>(
- new MediaCodecInfoWriter(info.get()));
-}
-
// legacy method for non-advanced codecs
ssize_t MediaCodecList::findCodecByType(
const char *type, bool encoder, size_t startIndex) const {
@@ -307,11 +307,8 @@
//static
void MediaCodecList::findMatchingCodecs(
const char *mime, bool encoder, uint32_t flags,
- Vector<AString> *matches, Vector<AString> *owners) {
+ Vector<AString> *matches) {
matches->clear();
- if (owners != nullptr) {
- owners->clear();
- }
const sp<IMediaCodecList> list = getInstance();
if (list == nullptr) {
@@ -337,9 +334,6 @@
ALOGV("skipping SW codec '%s'", componentName.c_str());
} else {
matches->push(componentName);
- if (owners != nullptr) {
- owners->push(AString(info->getOwnerName()));
- }
ALOGV("matching '%s'", componentName.c_str());
}
}
@@ -350,7 +344,4 @@
}
}
-MediaCodecListBuilderBase::~MediaCodecListBuilderBase() {
-}
-
} // namespace android
diff --git a/media/libstagefright/MediaCodecListWriter.cpp b/media/libstagefright/MediaCodecListWriter.cpp
new file mode 100644
index 0000000..b32e470
--- /dev/null
+++ b/media/libstagefright/MediaCodecListWriter.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012, 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 "MediaCodecListWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodecListWriter.h>
+#include <media/MediaCodecInfo.h>
+
+namespace android {
+
+void MediaCodecListWriter::addGlobalSetting(
+ const char* key, const char* value) {
+ mGlobalSettings.emplace_back(key, value);
+}
+
+std::unique_ptr<MediaCodecInfoWriter>
+ MediaCodecListWriter::addMediaCodecInfo() {
+ sp<MediaCodecInfo> info = new MediaCodecInfo();
+ mCodecInfos.push_back(info);
+ return std::unique_ptr<MediaCodecInfoWriter>(
+ new MediaCodecInfoWriter(info.get()));
+}
+
+void MediaCodecListWriter::writeGlobalSettings(
+ const sp<AMessage> &globalSettings) const {
+ for (const std::pair<std::string, std::string> &kv : mGlobalSettings) {
+ globalSettings->setString(kv.first.c_str(), kv.second.c_str());
+ }
+}
+
+void MediaCodecListWriter::writeCodecInfos(
+ std::vector<sp<MediaCodecInfo>> *codecInfos) const {
+ for (const sp<MediaCodecInfo> &info : mCodecInfos) {
+ codecInfos->push_back(info);
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index af8f539..04f6ade 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -24,11 +24,12 @@
namespace android {
-bool MakeAVCCodecSpecificData(MetaDataBase &meta, const sp<ABuffer> &accessUnit) {
+bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
int32_t width;
int32_t height;
int32_t sarWidth;
int32_t sarHeight;
+ sp<ABuffer> accessUnit = new ABuffer((void*)data, size);
sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
if (csd == nullptr) {
return false;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f6fc813..4a7d6ca 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "NuMediaExtractor"
#include <utils/Log.h>
@@ -205,6 +205,15 @@
return OK;
}
+void NuMediaExtractor::disconnect() {
+ if (mDataSource != NULL) {
+ // disconnect data source
+ if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
+ static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
+ }
+ }
+}
+
status_t NuMediaExtractor::updateDurationAndBitrate() {
if (mImpl->countTracks() > kMaxTrackCount) {
return ERROR_UNSUPPORTED;
@@ -298,6 +307,26 @@
return OK;
}
+status_t NuMediaExtractor::getExifOffsetSize(off64_t *offset, size_t *size) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mImpl == NULL) {
+ return -EINVAL;
+ }
+
+ sp<MetaData> meta = mImpl->getMetaData();
+
+ int64_t exifOffset, exifSize;
+ if (meta->findInt64(kKeyExifOffset, &exifOffset)
+ && meta->findInt64(kKeyExifSize, &exifSize)) {
+ *offset = (off64_t) exifOffset;
+ *size = (size_t) exifSize;
+
+ return OK;
+ }
+ return ERROR_UNSUPPORTED;
+}
+
status_t NuMediaExtractor::selectTrack(size_t index,
int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/StagefrightPluginLoader.cpp b/media/libstagefright/StagefrightPluginLoader.cpp
new file mode 100644
index 0000000..7f13f87
--- /dev/null
+++ b/media/libstagefright/StagefrightPluginLoader.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018, 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 "StagefrightPluginLoader"
+#include <utils/Log.h>
+
+#include <dlfcn.h>
+
+#include "StagefrightPluginLoader.h"
+
+namespace android {
+
+/* static */ Mutex StagefrightPluginLoader::sMutex;
+/* static */ std::unique_ptr<StagefrightPluginLoader> StagefrightPluginLoader::sInstance;
+
+StagefrightPluginLoader::StagefrightPluginLoader(const char *libPath)
+ : mCreateCodec(nullptr),
+ mCreateBuilder(nullptr) {
+ mLibHandle = dlopen(libPath, RTLD_NOW | RTLD_NODELETE);
+ if (mLibHandle == nullptr) {
+ ALOGD("Failed to load library: %s (%s)", libPath, dlerror());
+ return;
+ }
+ mCreateCodec = (CodecBase::CreateCodecFunc)dlsym(mLibHandle, "CreateCodec");
+ if (mCreateCodec == nullptr) {
+ ALOGD("Failed to find symbol: CreateCodec (%s)", dlerror());
+ }
+ mCreateBuilder = (MediaCodecListBuilderBase::CreateBuilderFunc)dlsym(
+ mLibHandle, "CreateBuilder");
+ if (mCreateBuilder == nullptr) {
+ ALOGD("Failed to find symbol: CreateBuilder (%s)", dlerror());
+ }
+}
+
+StagefrightPluginLoader::~StagefrightPluginLoader() {
+ if (mLibHandle != nullptr) {
+ ALOGV("Closing handle");
+ dlclose(mLibHandle);
+ }
+}
+
+CodecBase *StagefrightPluginLoader::createCodec() {
+ if (mLibHandle == nullptr || mCreateCodec == nullptr) {
+ ALOGD("Handle or CreateCodec symbol is null");
+ return nullptr;
+ }
+ return mCreateCodec();
+}
+
+MediaCodecListBuilderBase *StagefrightPluginLoader::createBuilder() {
+ if (mLibHandle == nullptr || mCreateBuilder == nullptr) {
+ ALOGD("Handle or CreateBuilder symbol is null");
+ return nullptr;
+ }
+ return mCreateBuilder();
+}
+
+//static
+const std::unique_ptr<StagefrightPluginLoader> &StagefrightPluginLoader::GetCCodecInstance() {
+ Mutex::Autolock _l(sMutex);
+ if (!sInstance) {
+ ALOGV("Loading library");
+ sInstance.reset(new StagefrightPluginLoader("libstagefright_ccodec.so"));
+ }
+ return sInstance;
+}
+
+} // namespace android
diff --git a/media/libstagefright/StagefrightPluginLoader.h b/media/libstagefright/StagefrightPluginLoader.h
new file mode 100644
index 0000000..2746756
--- /dev/null
+++ b/media/libstagefright/StagefrightPluginLoader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018, 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.
+ */
+
+#ifndef STAGEFRIGHT_PLUGIN_LOADER_H_
+
+#define STAGEFRIGHT_PLUGIN_LOADER_H_
+
+#include <media/stagefright/CodecBase.h>
+#include <media/stagefright/MediaCodecListWriter.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+class StagefrightPluginLoader {
+public:
+ static const std::unique_ptr<StagefrightPluginLoader> &GetCCodecInstance();
+ ~StagefrightPluginLoader();
+
+ CodecBase *createCodec();
+ MediaCodecListBuilderBase *createBuilder();
+private:
+ explicit StagefrightPluginLoader(const char *libPath);
+
+ static Mutex sMutex;
+ static std::unique_ptr<StagefrightPluginLoader> sInstance;
+
+ void *mLibHandle;
+ CodecBase::CreateCodecFunc mCreateCodec;
+ MediaCodecListBuilderBase::CreateBuilderFunc mCreateBuilder;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_PLUGIN_LOADER_H_
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 4a93051..0c6e988 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -665,13 +665,13 @@
}
if (!strncasecmp("image/", mime, 6)) {
- int32_t gridWidth, gridHeight, gridRows, gridCols;
- if (meta->findInt32(kKeyGridWidth, &gridWidth)
- && meta->findInt32(kKeyGridHeight, &gridHeight)
+ int32_t tileWidth, tileHeight, gridRows, gridCols;
+ if (meta->findInt32(kKeyTileWidth, &tileWidth)
+ && meta->findInt32(kKeyTileHeight, &tileHeight)
&& meta->findInt32(kKeyGridRows, &gridRows)
&& meta->findInt32(kKeyGridCols, &gridCols)) {
- msg->setInt32("grid-width", gridWidth);
- msg->setInt32("grid-height", gridHeight);
+ msg->setInt32("tile-width", tileWidth);
+ msg->setInt32("tile-height", tileHeight);
msg->setInt32("grid-rows", gridRows);
msg->setInt32("grid-cols", gridCols);
}
@@ -1341,12 +1341,12 @@
if (msg->findInt32("is-default", &isPrimary) && isPrimary) {
meta->setInt32(kKeyTrackIsDefault, 1);
}
- int32_t gridWidth, gridHeight, gridRows, gridCols;
- if (msg->findInt32("grid-width", &gridWidth)) {
- meta->setInt32(kKeyGridWidth, gridWidth);
+ int32_t tileWidth, tileHeight, gridRows, gridCols;
+ if (msg->findInt32("tile-width", &tileWidth)) {
+ meta->setInt32(kKeyTileWidth, tileWidth);
}
- if (msg->findInt32("grid-height", &gridHeight)) {
- meta->setInt32(kKeyGridHeight, gridHeight);
+ if (msg->findInt32("tile-height", &tileHeight)) {
+ meta->setInt32(kKeyTileHeight, tileHeight);
}
if (msg->findInt32("grid-rows", &gridRows)) {
meta->setInt32(kKeyGridRows, gridRows);
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index 388ed6b..4f46be7 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -6,6 +6,7 @@
},
srcs: [
+ "Conversion.cpp",
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
"WProducerListener.cpp",
@@ -42,8 +43,9 @@
],
export_shared_lib_headers: [
- "libstagefright_foundation",
+ "libgui",
"libhidlmemory",
+ "libstagefright_foundation",
],
cflags: [
diff --git a/media/libstagefright/bqhelper/Conversion.cpp b/media/libstagefright/bqhelper/Conversion.cpp
new file mode 100644
index 0000000..ffed005
--- /dev/null
+++ b/media/libstagefright/bqhelper/Conversion.cpp
@@ -0,0 +1,1542 @@
+/*
+ * Copyright 2018, 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.
+ */
+
+#include <media/stagefright/bqhelper/Conversion.h>
+
+namespace android {
+namespace conversion {
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+native_handle_t* native_handle_create_from_fd(int fd) {
+ if (fd < 2) {
+ return native_handle_create(0, 0);
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (nh == nullptr) {
+ return nullptr;
+ }
+ nh->data[0] = fd;
+ return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+int native_handle_read_fd(native_handle_t const* nh, int index) {
+ return ((nh == nullptr) || (nh->numFds == 0) ||
+ (nh->numFds <= index) || (index < 0)) ?
+ -1 : nh->data[index];
+}
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ * input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ * corresponds to the input. The lifetime of the output does not depend on the
+ * lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ * that cannot be copied and/or moved efficiently, or when there are multiple
+ * output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ * `TargetType` that cannot be copied and/or moved efficiently, or when there
+ * are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: Return<void> -> ::android::binder::Status
+::android::binder::Status toBinderStatus(
+ Return<void> const& t) {
+ return ::android::binder::Status::fromExceptionCode(
+ t.isOk() ? OK : UNKNOWN_ERROR,
+ t.description().c_str());
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+status_t toStatusT(Return<void> const& t) {
+ return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+hidl_handle inHidlHandle(native_handle_t const* nh) {
+ return hidl_handle(nh);
+}
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+Dataspace toHardwareDataspace(int32_t l) {
+ return static_cast<Dataspace>(l);
+}
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+int32_t toRawDataspace(Dataspace const& t) {
+ return static_cast<int32_t>(t);
+}
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+ return t;
+}
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.resize(size);
+ uint8_t const* src = static_cast<uint8_t const*>(l);
+ std::copy(src, src + size, t.data());
+ return t;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+ t->attr.width = l.getWidth();
+ t->attr.height = l.getHeight();
+ t->attr.stride = l.getStride();
+ t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+ t->attr.layerCount = l.getLayerCount();
+ t->attr.usage = l.getUsage();
+ t->attr.id = l.getId();
+ t->attr.generationNumber = l.getGenerationNumber();
+ t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+ native_handle_t* handle = t.nativeHandle == nullptr ?
+ nullptr : native_handle_clone(t.nativeHandle);
+
+ size_t const numInts = 12 + (handle ? handle->numInts : 0);
+ int32_t* ints = new int32_t[numInts];
+
+ size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+ int* fds = new int[numFds];
+
+ ints[0] = 'GBFR';
+ ints[1] = static_cast<int32_t>(t.attr.width);
+ ints[2] = static_cast<int32_t>(t.attr.height);
+ ints[3] = static_cast<int32_t>(t.attr.stride);
+ ints[4] = static_cast<int32_t>(t.attr.format);
+ ints[5] = static_cast<int32_t>(t.attr.layerCount);
+ ints[6] = static_cast<int32_t>(t.attr.usage);
+ ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+ ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+ ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+ ints[10] = 0;
+ ints[11] = 0;
+ if (handle) {
+ ints[10] = static_cast<int32_t>(handle->numFds);
+ ints[11] = static_cast<int32_t>(handle->numInts);
+ int* intsStart = handle->data + handle->numFds;
+ std::copy(handle->data, intsStart, fds);
+ std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+ }
+
+ void const* constBuffer = static_cast<void const*>(ints);
+ size_t size = numInts * sizeof(int32_t);
+ int const* constFds = static_cast<int const*>(fds);
+ status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+ delete [] fds;
+ delete [] ints;
+ native_handle_delete(handle);
+ return status == NO_ERROR;
+}
+
+/**
+ * Conversion functions for types outside media
+ * ============================================
+ *
+ * Some objects in libui and libgui that were made to go through binder calls do
+ * not expose ways to read or write their fields to the public. To pass an
+ * object of this kind through the HIDL boundary, translation functions need to
+ * work around the access restriction by using the publicly available
+ * `flatten()` and `unflatten()` functions.
+ *
+ * All `flatten()` and `unflatten()` overloads follow the same convention as
+ * follows:
+ *
+ * status_t flatten(ObjectType const& object,
+ * [OtherType const& other, ...]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * status_t unflatten(ObjectType* object,
+ * [OtherType* other, ...,]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * The number of `other` parameters varies depending on the `ObjectType`. For
+ * example, in the process of unflattening an object that contains
+ * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
+ * be created.
+ *
+ * The last four parameters always work the same way in all overloads of
+ * `flatten()` and `unflatten()`:
+ * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
+ * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
+ * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
+ * size (in ints) of the fd buffer pointed to by `fds`.
+ * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
+ * from, `size` is the size (in bytes) of the non-fd buffer pointed to by
+ * `buffer`, `fds` is the pointer to the fd buffer to be read from, and
+ * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
+ * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
+ * will be advanced, while `size` and `numFds` will be decreased to reflect
+ * how much storage/data of the two buffers (fd and non-fd) have been used.
+ * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
+ * `numFds` are invalid.
+ *
+ * The return value of a successful `flatten()` or `unflatten()` call will be
+ * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
+ *
+ * For each object type that supports flattening, there will be two accompanying
+ * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
+ * return the size of the non-fd buffer that the object will need for
+ * flattening. `getFdCount()` will return the size of the fd buffer that the
+ * object will need for flattening.
+ *
+ * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
+ * `flatten()` and `unflatten()`, are similar to functions of the same name in
+ * the abstract class `Flattenable`. The only difference is that functions in
+ * this file are not member functions of the object type. For example, we write
+ *
+ * flatten(x, buffer, size, fds, numFds)
+ *
+ * instead of
+ *
+ * x.flatten(buffer, size, fds, numFds)
+ *
+ * because we cannot modify the type of `x`.
+ *
+ * There is one exception to the naming convention: `hidl_handle` that
+ * represents a fence. The four functions for this "Fence" type have the word
+ * "Fence" attched to their names because the object type, which is
+ * `hidl_handle`, does not carry the special meaning that the object itself can
+ * only contain zero or one file descriptor.
+ */
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+ return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+size_t getFenceFdCount(hidl_handle const& fence) {
+ return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numFdsInHandle;
+ FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+ if (numFdsInHandle > 1) {
+ return BAD_VALUE;
+ }
+
+ if (numFds < numFdsInHandle) {
+ return NO_MEMORY;
+ }
+
+ if (numFdsInHandle) {
+ *nh = native_handle_create_from_fd(*fds);
+ if (*nh == nullptr) {
+ return NO_MEMORY;
+ }
+ *fence = *nh;
+ ++fds;
+ --numFds;
+ } else {
+ *nh = nullptr;
+ *fence = hidl_handle();
+ }
+
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] t The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFenceFlattenedSize(fence) ||
+ numFds < getFenceFdCount(fence)) {
+ return NO_MEMORY;
+ }
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size,
+ static_cast<uint32_t>(getFenceFdCount(fence)));
+ int fd = native_handle_read_fd(fence);
+ if (fd != -1) {
+ *fds = fd;
+ ++fds;
+ --numFds;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+ != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+bool convertTo(Fence* l, hidl_handle const& t) {
+ int fd = native_handle_read_fd(t);
+ if (fd != -1) {
+ fd = dup(fd);
+ if (fd == -1) {
+ return false;
+ }
+ }
+ native_handle_t* nh = native_handle_create_from_fd(fd);
+ if (nh == nullptr) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return false;
+ }
+
+ size_t const baseSize = getFenceFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ size_t const baseNumFds = getFenceFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+ native_handle_delete(nh);
+ return false;
+ }
+ native_handle_delete(nh);
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ constexpr size_t min = sizeof(t.state);
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ return min;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ return min + getFenceFlattenedSize(t.fence);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ return min + sizeof(
+ ::android::FenceTime::Snapshot::signalTime);
+ }
+ return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ return t.state ==
+ HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+ getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`.
+ */
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::EMPTY);
+ return NO_ERROR;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::FENCE);
+ return flattenFence(t.fence, buffer, size, fds, numFds);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+ FlattenableUtils::write(buffer, size, t.signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `FenceTimeSnapshot`.
+ *
+ * \param[out] t The destination `FenceTimeSnapshot`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and the constructed snapshot contains a
+ * file descriptor, \p nh will be created to hold that file descriptor. In this
+ * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < sizeof(t->state)) {
+ return NO_MEMORY;
+ }
+
+ *nh = nullptr;
+ ::android::FenceTime::Snapshot::State state;
+ FlattenableUtils::read(buffer, size, state);
+ switch (state) {
+ case ::android::FenceTime::Snapshot::State::EMPTY:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
+ return NO_ERROR;
+ case ::android::FenceTime::Snapshot::State::FENCE:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
+ return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
+ case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
+ if (size < sizeof(t->signalTimeNs)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+ return sizeof(uint64_t) + // mFrameNumber
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(nsecs_t) + // mPostedTime
+ sizeof(nsecs_t) + // mRequestedPresentTime
+ sizeof(nsecs_t) + // mLatchTime
+ sizeof(nsecs_t) + // mFirstRefreshStartTime
+ sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return minFlattenedSize(t) +
+ getFlattenedSize(t.gpuCompositionDoneFence) +
+ getFlattenedSize(t.displayPresentFence) +
+ getFlattenedSize(t.displayRetireFence) +
+ getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return getFdCount(t.gpuCompositionDoneFence) +
+ getFdCount(t.displayPresentFence) +
+ getFdCount(t.displayRetireFence) +
+ getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Unflatten `FrameEventsDelta`.
+ *
+ * \param[out] t The destination `FrameEventsDelta`.
+ * \param[out] nh The underlying array of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
+ * populated with `nullptr` or newly created handles. Each non-null slot in \p
+ * nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+ std::vector<native_handle_t*>* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->frameNumber);
+
+ // These were written as uint8_t for alignment.
+ uint8_t temp = 0;
+ FlattenableUtils::read(buffer, size, temp);
+ size_t index = static_cast<size_t>(temp);
+ if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->index = static_cast<uint32_t>(index);
+
+ FlattenableUtils::read(buffer, size, temp);
+ t->addPostCompositeCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addRetireCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addReleaseCalled = static_cast<bool>(temp);
+
+ FlattenableUtils::read(buffer, size, t->postedTimeNs);
+ FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
+ FlattenableUtils::read(buffer, size, t->latchTimeNs);
+ FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
+ tSnapshot[0] = &t->gpuCompositionDoneFence;
+ tSnapshot[1] = &t->displayPresentFence;
+ tSnapshot[2] = &t->displayRetireFence;
+ tSnapshot[3] = &t->releaseFence;
+ nh->resize(4);
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = unflatten(
+ tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (snapshotIndex > 0) {
+ --snapshotIndex;
+ if ((*nh)[snapshotIndex] != nullptr) {
+ native_handle_delete((*nh)[snapshotIndex]);
+ }
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+// FrameEventsDelta::flatten
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t numFds) {
+ // Check that t.index is within a valid range.
+ if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+ || t.index > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, t.frameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, t.postedTimeNs);
+ FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+ FlattenableUtils::write(buffer, size, t.latchTimeNs);
+ FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+ tSnapshot[0] = &t.gpuCompositionDoneFence;
+ tSnapshot[1] = &t.displayPresentFence;
+ tSnapshot[2] = &t.displayRetireFence;
+ tSnapshot[3] = &t.releaseFence;
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = flatten(
+ *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t size = 4 + // mDeltas.size()
+ sizeof(t.compositorTiming);
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ size += getFlattenedSize(t.deltas[i]);
+ }
+ return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t numFds = 0;
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ numFds += getFdCount(t.deltas[i]);
+ }
+ return numFds;
+}
+
+/**
+ * \brief Unflatten `FrameEventHistoryDelta`.
+ *
+ * \param[out] t The destination `FrameEventHistoryDelta`.
+ * \param[out] nh The underlying array of arrays of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
+ * newly created handles. The second dimension of \p nh will be 4. Each non-null
+ * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->compositorTiming);
+
+ uint32_t deltaCount = 0;
+ FlattenableUtils::read(buffer, size, deltaCount);
+ if (static_cast<size_t>(deltaCount) >
+ ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->deltas.resize(deltaCount);
+ nh->resize(deltaCount);
+ for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
+ status_t status = unflatten(
+ &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+status_t flatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+ for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+ status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `::android::FrameEventHistoryData` in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `::android::FrameEventHistoryDelta`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ ::android::FrameEventHistoryDelta const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+bool convertTo(
+ ::android::FrameEventHistoryDelta* l,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Return the size of the buffer required to flatten `Region`.
+ *
+ * \param[in] t The input `Region`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(Region const& t) {
+ return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
+}
+
+/**
+ * \brief Unflatten `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t unflatten(Region* t, void const*& buffer, size_t& size) {
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(Rect)) {
+ return NO_MEMORY;
+ }
+ if (numRects > (UINT32_MAX / sizeof(Rect))) {
+ return NO_MEMORY;
+ }
+
+ t->resize(numRects);
+ for (size_t r = 0; r < numRects; ++r) {
+ ::android::Rect rect(::android::Rect::EMPTY_RECT);
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ (*t)[r] = Rect{
+ static_cast<int32_t>(rect.left),
+ static_cast<int32_t>(rect.top),
+ static_cast<int32_t>(rect.right),
+ static_cast<int32_t>(rect.bottom)};
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `Region`.
+ *
+ * \param[in] t The source `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flatten(Region const& t, void*& buffer, size_t& size) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
+ for (size_t r = 0; r < t.size(); ++r) {
+ ::android::Rect rect(
+ static_cast<int32_t>(t[r].left),
+ static_cast<int32_t>(t[r].top),
+ static_cast<int32_t>(t[r].right),
+ static_cast<int32_t>(t[r].bottom));
+ status_t status = rect.flatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Convert `::android::Region` to `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in] l The source `::android::Region`.
+ */
+// convert: ::android::Region -> Region
+bool convertTo(Region* t, ::android::Region const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (l.flatten(buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (unflatten(t, constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `Region` to `::android::Region`.
+ *
+ * \param[out] l The destination `::android::Region`.
+ * \param[in] t The source `Region`.
+ */
+// convert: Region -> ::android::Region
+bool convertTo(::android::Region* l, Region const& t) {
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (flatten(t, buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (l->unflatten(constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
+ sizeof(android_dataspace) + // dataSpace
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Return the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
+ return minFlattenedSize(t) +
+ getFenceFlattenedSize(t.fence) +
+ getFlattenedSize(t.surfaceDamage) +
+ sizeof(HdrMetadata::validTypes);
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+ return getFenceFdCount(t.fence);
+}
+
+/**
+ * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence`. */
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+ native_handle_t** nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.timestamp);
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
+ FlattenableUtils::write(buffer, size,
+ static_cast<android_dataspace_t>(t.dataSpace));
+ FlattenableUtils::write(buffer, size, ::android::Rect(
+ static_cast<int32_t>(t.crop.left),
+ static_cast<int32_t>(t.crop.top),
+ static_cast<int32_t>(t.crop.right),
+ static_cast<int32_t>(t.crop.bottom)));
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
+ FlattenableUtils::write(buffer, size, t.transform);
+ FlattenableUtils::write(buffer, size, t.stickyTransform);
+ FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
+
+ *nh = t.fence.getNativeHandle() == nullptr ?
+ nullptr : native_handle_clone(t.fence);
+ status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = flatten(t.surfaceDamage, buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->timestamp);
+ int lIsAutoTimestamp;
+ FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+ t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+ android_dataspace_t lDataSpace;
+ FlattenableUtils::read(buffer, size, lDataSpace);
+ t->dataSpace = static_cast<Dataspace>(lDataSpace);
+ Rect lCrop;
+ FlattenableUtils::read(buffer, size, lCrop);
+ t->crop = Rect{
+ static_cast<int32_t>(lCrop.left),
+ static_cast<int32_t>(lCrop.top),
+ static_cast<int32_t>(lCrop.right),
+ static_cast<int32_t>(lCrop.bottom)};
+ int lScalingMode;
+ FlattenableUtils::read(buffer, size, lScalingMode);
+ t->scalingMode = static_cast<int32_t>(lScalingMode);
+ FlattenableUtils::read(buffer, size, t->transform);
+ FlattenableUtils::read(buffer, size, t->stickyTransform);
+ FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+ status_t status = unflattenFence(&(t->fence), nh,
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ // HdrMetadata ignored
+ return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+bool wrapAs(
+ HGraphicBufferProducer::QueueBufferInput* t,
+ native_handle_t** nh,
+ BGraphicBufferProducer::QueueBufferInput const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
+ * `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If `t.fence` has a valid file descriptor, it will be duplicated.
+ */
+bool convertTo(
+ BGraphicBufferProducer::QueueBufferInput* l,
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ native_handle_t* nh;
+ if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
+ return false;
+ }
+
+ native_handle_delete(nh);
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+// wrap: BGraphicBufferProducer::QueueBufferOutput ->
+// HGraphicBufferProducer::QueueBufferOutput
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ BGraphicBufferProducer::QueueBufferOutput const& l) {
+ if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
+ return false;
+ }
+ t->width = l.width;
+ t->height = l.height;
+ t->transformHint = l.transformHint;
+ t->numPendingBuffers = l.numPendingBuffers;
+ t->nextFrameNumber = l.nextFrameNumber;
+ t->bufferReplaced = l.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// BGraphicBufferProducer::QueueBufferOutput
+bool convertTo(
+ BGraphicBufferProducer::QueueBufferOutput* l,
+ HGraphicBufferProducer::QueueBufferOutput const& t) {
+ if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+ return false;
+ }
+ l->width = t.width;
+ l->height = t.height;
+ l->transformHint = t.transformHint;
+ l->numPendingBuffers = t.numPendingBuffers;
+ l->nextFrameNumber = t.nextFrameNumber;
+ l->bufferReplaced = t.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l) {
+ switch (l) {
+ case BGraphicBufferProducer::DisconnectMode::Api:
+ return HGraphicBufferProducer::DisconnectMode::API;
+ case BGraphicBufferProducer::DisconnectMode::AllLocal:
+ return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+ }
+ return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
+ * `BGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
+ */
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+ HGraphicBufferProducer::DisconnectMode t) {
+ switch (t) {
+ case HGraphicBufferProducer::DisconnectMode::API:
+ return BGraphicBufferProducer::DisconnectMode::Api;
+ case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
+ return BGraphicBufferProducer::DisconnectMode::AllLocal;
+ }
+ return BGraphicBufferProducer::DisconnectMode::Api;
+}
+
+} // namespace conversion
+} // namespace android
+
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
index c15fafa..60d8c1e 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef MEDIA_STAGEFRIGHT_CONVERSION_H_
-#define MEDIA_STAGEFRIGHT_CONVERSION_H_
+#ifndef MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
+#define MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
#include <vector>
#include <list>
@@ -83,17 +83,7 @@
*
* This function does not duplicate the file descriptor.
*/
-inline native_handle_t* native_handle_create_from_fd(int fd) {
- if (fd < 2) {
- return native_handle_create(0, 0);
- }
- native_handle_t* nh = native_handle_create(1, 0);
- if (nh == nullptr) {
- return nullptr;
- }
- nh->data[0] = fd;
- return nh;
-}
+native_handle_t* native_handle_create_from_fd(int fd);
/**
* \brief Extract a file descriptor from a native handle.
@@ -106,11 +96,7 @@
*
* This function does not duplicate the file descriptor.
*/
-inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
- return ((nh == nullptr) || (nh->numFds == 0) ||
- (nh->numFds <= index) || (index < 0)) ?
- -1 : nh->data[index];
-}
+int native_handle_read_fd(native_handle_t const* nh, int index = 0);
/**
* Conversion functions
@@ -151,12 +137,7 @@
* \return The corresponding `binder::Status`.
*/
// convert: Return<void> -> ::android::binder::Status
-inline ::android::binder::Status toBinderStatus(
- Return<void> const& t) {
- return ::android::binder::Status::fromExceptionCode(
- t.isOk() ? OK : UNKNOWN_ERROR,
- t.description().c_str());
-}
+::android::binder::Status toBinderStatus(Return<void> const& t);
/**
* \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
@@ -165,9 +146,7 @@
* \return The corresponding `status_t`.
*/
// convert: Return<void> -> status_t
-inline status_t toStatusT(Return<void> const& t) {
- return t.isOk() ? OK : UNKNOWN_ERROR;
-}
+status_t toStatusT(Return<void> const& t);
/**
* \brief Wrap `native_handle_t*` in `hidl_handle`.
@@ -176,9 +155,7 @@
* \return The `hidl_handle` that points to \p nh.
*/
// wrap: native_handle_t* -> hidl_handle
-inline hidl_handle inHidlHandle(native_handle_t const* nh) {
- return hidl_handle(nh);
-}
+hidl_handle inHidlHandle(native_handle_t const* nh);
/**
* \brief Convert `int32_t` to `Dataspace`.
@@ -187,9 +164,7 @@
* \result The corresponding `Dataspace`.
*/
// convert: int32_t -> Dataspace
-inline Dataspace toHardwareDataspace(int32_t l) {
- return static_cast<Dataspace>(l);
-}
+Dataspace toHardwareDataspace(int32_t l);
/**
* \brief Convert `Dataspace` to `int32_t`.
@@ -198,9 +173,7 @@
* \result The corresponding `int32_t`.
*/
// convert: Dataspace -> int32_t
-inline int32_t toRawDataspace(Dataspace const& t) {
- return static_cast<int32_t>(t);
-}
+int32_t toRawDataspace(Dataspace const& t);
/**
* \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
@@ -210,11 +183,7 @@
* \return A `hidl_vec<uint8_t>` that points to the buffer.
*/
// wrap: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
- return t;
-}
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size);
/**
* \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
@@ -224,13 +193,7 @@
* \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
*/
// convert: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.resize(size);
- uint8_t const* src = static_cast<uint8_t const*>(l);
- std::copy(src, src + size, t.data());
- return t;
-}
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size);
/**
* \brief Wrap `GraphicBuffer` in `AnwBuffer`.
@@ -239,17 +202,7 @@
* \param[in] l The source `GraphicBuffer`.
*/
// wrap: GraphicBuffer -> AnwBuffer
-inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
- t->attr.width = l.getWidth();
- t->attr.height = l.getHeight();
- t->attr.stride = l.getStride();
- t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
- t->attr.layerCount = l.getLayerCount();
- t->attr.usage = l.getUsage();
- t->attr.id = l.getId();
- t->attr.generationNumber = l.getGenerationNumber();
- t->nativeHandle = hidl_handle(l.handle);
-}
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l);
/**
* \brief Convert `AnwBuffer` to `GraphicBuffer`.
@@ -261,46 +214,7 @@
*/
// convert: AnwBuffer -> GraphicBuffer
// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
-inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
- native_handle_t* handle = t.nativeHandle == nullptr ?
- nullptr : native_handle_clone(t.nativeHandle);
-
- size_t const numInts = 12 + (handle ? handle->numInts : 0);
- int32_t* ints = new int32_t[numInts];
-
- size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
- int* fds = new int[numFds];
-
- ints[0] = 'GBFR';
- ints[1] = static_cast<int32_t>(t.attr.width);
- ints[2] = static_cast<int32_t>(t.attr.height);
- ints[3] = static_cast<int32_t>(t.attr.stride);
- ints[4] = static_cast<int32_t>(t.attr.format);
- ints[5] = static_cast<int32_t>(t.attr.layerCount);
- ints[6] = static_cast<int32_t>(t.attr.usage);
- ints[7] = static_cast<int32_t>(t.attr.id >> 32);
- ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
- ints[9] = static_cast<int32_t>(t.attr.generationNumber);
- ints[10] = 0;
- ints[11] = 0;
- if (handle) {
- ints[10] = static_cast<int32_t>(handle->numFds);
- ints[11] = static_cast<int32_t>(handle->numInts);
- int* intsStart = handle->data + handle->numFds;
- std::copy(handle->data, intsStart, fds);
- std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
- }
-
- void const* constBuffer = static_cast<void const*>(ints);
- size_t size = numInts * sizeof(int32_t);
- int const* constFds = static_cast<int const*>(fds);
- status_t status = l->unflatten(constBuffer, size, constFds, numFds);
-
- delete [] fds;
- delete [] ints;
- native_handle_delete(handle);
- return status == NO_ERROR;
-}
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t);
/**
* Conversion functions for types outside media
@@ -387,9 +301,7 @@
* bytes required to store the number of file descriptors contained in the fd
* part of the flat buffer.
*/
-inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
- return 4;
-};
+size_t getFenceFlattenedSize(hidl_handle const& fence);
/**
* \brief Return the number of file descriptors contained in a fence.
@@ -398,9 +310,7 @@
* \return `0` if \p fence does not contain a valid file descriptor, or `1`
* otherwise.
*/
-inline size_t getFenceFdCount(hidl_handle const& fence) {
- return native_handle_read_fd(fence) == -1 ? 0 : 1;
-}
+size_t getFenceFdCount(hidl_handle const& fence);
/**
* \brief Unflatten `Fence` to `hidl_handle`.
@@ -417,38 +327,8 @@
* native handle, which needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- uint32_t numFdsInHandle;
- FlattenableUtils::read(buffer, size, numFdsInHandle);
-
- if (numFdsInHandle > 1) {
- return BAD_VALUE;
- }
-
- if (numFds < numFdsInHandle) {
- return NO_MEMORY;
- }
-
- if (numFdsInHandle) {
- *nh = native_handle_create_from_fd(*fds);
- if (*nh == nullptr) {
- return NO_MEMORY;
- }
- *fence = *nh;
- ++fds;
- --numFds;
- } else {
- *nh = nullptr;
- *fence = hidl_handle();
- }
-
- return NO_ERROR;
-}
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `hidl_handle` as `Fence`.
@@ -460,24 +340,8 @@
* \param[in,out] numFds The size of the flat fd buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t flattenFence(hidl_handle const& fence,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFenceFlattenedSize(fence) ||
- numFds < getFenceFdCount(fence)) {
- return NO_MEMORY;
- }
- // Cast to uint32_t since the size of a size_t can vary between 32- and
- // 64-bit processes
- FlattenableUtils::write(buffer, size,
- static_cast<uint32_t>(getFenceFdCount(fence)));
- int fd = native_handle_read_fd(fence);
- if (fd != -1) {
- *fds = fd;
- ++fds;
- --numFds;
- }
- return NO_ERROR;
-}
+status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Wrap `Fence` in `hidl_handle`.
@@ -490,40 +354,7 @@
* deleted manually with `native_handle_delete()` afterwards.
*/
// wrap: Fence -> hidl_handle
-inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
- != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l);
/**
* \brief Convert `hidl_handle` to `Fence`.
@@ -535,58 +366,7 @@
* If \p t contains a valid file descriptor, it will be duplicated.
*/
// convert: hidl_handle -> Fence
-inline bool convertTo(Fence* l, hidl_handle const& t) {
- int fd = native_handle_read_fd(t);
- if (fd != -1) {
- fd = dup(fd);
- if (fd == -1) {
- return false;
- }
- }
- native_handle_t* nh = native_handle_create_from_fd(fd);
- if (nh == nullptr) {
- if (fd != -1) {
- close(fd);
- }
- return false;
- }
-
- size_t const baseSize = getFenceFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- native_handle_delete(nh);
- return false;
- }
-
- size_t const baseNumFds = getFenceFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- native_handle_delete(nh);
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
- native_handle_delete(nh);
- return false;
- }
- native_handle_delete(nh);
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(Fence* l, hidl_handle const& t);
// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
@@ -597,20 +377,7 @@
* \param[in] t The input `FenceTimeSnapshot`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- constexpr size_t min = sizeof(t.state);
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- return min;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- return min + getFenceFlattenedSize(t.fence);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- return min + sizeof(
- ::android::FenceTime::Snapshot::signalTime);
- }
- return 0;
-}
+size_t getFlattenedSize(HGraphicBufferProducer::FenceTimeSnapshot const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -619,12 +386,7 @@
* \param[in] t The input `FenceTimeSnapshot`.
* \return The number of file descriptors contained in \p snapshot.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- return t.state ==
- HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
- getFenceFdCount(t.fence) : 0;
-}
+size_t getFdCount(HGraphicBufferProducer::FenceTimeSnapshot const& t);
/**
* \brief Flatten `FenceTimeSnapshot`.
@@ -639,29 +401,8 @@
* This function will duplicate the file descriptor in `t.fence` if `t.state ==
* FENCE`.
*/
-inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::EMPTY);
- return NO_ERROR;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::FENCE);
- return flattenFence(t.fence, buffer, size, fds, numFds);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
- FlattenableUtils::write(buffer, size, t.signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Unflatten `FenceTimeSnapshot`.
@@ -678,72 +419,20 @@
* file descriptor, \p nh will be created to hold that file descriptor. In this
* case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < sizeof(t->state)) {
- return NO_MEMORY;
- }
-
- *nh = nullptr;
- ::android::FenceTime::Snapshot::State state;
- FlattenableUtils::read(buffer, size, state);
- switch (state) {
- case ::android::FenceTime::Snapshot::State::EMPTY:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
- return NO_ERROR;
- case ::android::FenceTime::Snapshot::State::FENCE:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
- return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
- case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
- if (size < sizeof(t->signalTimeNs)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
/**
- * \brief Return a lower bound on the size of the non-fd buffer required to
- * flatten `FrameEventsDelta`.
- *
- * \param[in] t The input `FrameEventsDelta`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
- return sizeof(uint64_t) + // mFrameNumber
- sizeof(uint8_t) + // mIndex
- sizeof(uint8_t) + // mAddPostCompositeCalled
- sizeof(uint8_t) + // mAddRetireCalled
- sizeof(uint8_t) + // mAddReleaseCalled
- sizeof(nsecs_t) + // mPostedTime
- sizeof(nsecs_t) + // mRequestedPresentTime
- sizeof(nsecs_t) + // mLatchTime
- sizeof(nsecs_t) + // mFirstRefreshStartTime
- sizeof(nsecs_t); // mLastRefreshStartTime
-}
-
-/**
* \brief Return the size of the non-fd buffer required to flatten
* `FrameEventsDelta`.
*
* \param[in] t The input `FrameEventsDelta`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return minFlattenedSize(t) +
- getFlattenedSize(t.gpuCompositionDoneFence) +
- getFlattenedSize(t.displayPresentFence) +
- getFlattenedSize(t.displayRetireFence) +
- getFlattenedSize(t.releaseFence);
-};
+size_t getFlattenedSize(HGraphicBufferProducer::FrameEventsDelta const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -752,13 +441,7 @@
* \param[in] t The input `FrameEventsDelta`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return getFdCount(t.gpuCompositionDoneFence) +
- getFdCount(t.displayPresentFence) +
- getFdCount(t.displayRetireFence) +
- getFdCount(t.releaseFence);
-};
+size_t getFdCount(HGraphicBufferProducer::FrameEventsDelta const& t);
/**
* \brief Unflatten `FrameEventsDelta`.
@@ -775,60 +458,9 @@
* populated with `nullptr` or newly created handles. Each non-null slot in \p
* nh will need to be deleted manually with `native_handle_delete()`.
*/
-inline status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
std::vector<native_handle_t*>* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->frameNumber);
-
- // These were written as uint8_t for alignment.
- uint8_t temp = 0;
- FlattenableUtils::read(buffer, size, temp);
- size_t index = static_cast<size_t>(temp);
- if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->index = static_cast<uint32_t>(index);
-
- FlattenableUtils::read(buffer, size, temp);
- t->addPostCompositeCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addRetireCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addReleaseCalled = static_cast<bool>(temp);
-
- FlattenableUtils::read(buffer, size, t->postedTimeNs);
- FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
- FlattenableUtils::read(buffer, size, t->latchTimeNs);
- FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
- tSnapshot[0] = &t->gpuCompositionDoneFence;
- tSnapshot[1] = &t->displayPresentFence;
- tSnapshot[2] = &t->displayRetireFence;
- tSnapshot[3] = &t->releaseFence;
- nh->resize(4);
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = unflatten(
- tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- while (snapshotIndex > 0) {
- --snapshotIndex;
- if ((*nh)[snapshotIndex] != nullptr) {
- native_handle_delete((*nh)[snapshotIndex]);
- }
- }
- return status;
- }
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `FrameEventsDelta`.
@@ -844,47 +476,8 @@
*/
// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
// FrameEventsDelta::flatten
-inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t numFds) {
- // Check that t.index is within a valid range.
- if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
- || t.index > std::numeric_limits<uint8_t>::max()) {
- return BAD_VALUE;
- }
-
- FlattenableUtils::write(buffer, size, t.frameNumber);
-
- // These are static_cast to uint8_t for alignment.
- FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addRetireCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
-
- FlattenableUtils::write(buffer, size, t.postedTimeNs);
- FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
- FlattenableUtils::write(buffer, size, t.latchTimeNs);
- FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
- tSnapshot[0] = &t.gpuCompositionDoneFence;
- tSnapshot[1] = &t.displayPresentFence;
- tSnapshot[2] = &t.displayRetireFence;
- tSnapshot[3] = &t.releaseFence;
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = flatten(
- *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t numFds);
// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
@@ -895,15 +488,8 @@
* \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t size = 4 + // mDeltas.size()
- sizeof(t.compositorTiming);
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- size += getFlattenedSize(t.deltas[i]);
- }
- return size;
-}
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -912,14 +498,8 @@
* \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t numFds = 0;
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- numFds += getFdCount(t.deltas[i]);
- }
- return numFds;
-}
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
/**
* \brief Unflatten `FrameEventHistoryDelta`.
@@ -936,34 +516,10 @@
* newly created handles. The second dimension of \p nh will be 4. Each non-null
* slot in \p nh will need to be deleted manually with `native_handle_delete()`.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::FrameEventHistoryDelta* t,
std::vector<std::vector<native_handle_t*> >* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->compositorTiming);
-
- uint32_t deltaCount = 0;
- FlattenableUtils::read(buffer, size, deltaCount);
- if (static_cast<size_t>(deltaCount) >
- ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->deltas.resize(deltaCount);
- nh->resize(deltaCount);
- for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
- status_t status = unflatten(
- &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `FrameEventHistoryDelta`.
@@ -977,27 +533,9 @@
*
* This function will duplicate file descriptors contained in \p t.
*/
-inline status_t flatten(
+status_t flatten(
HGraphicBufferProducer::FrameEventHistoryDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.compositorTiming);
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
- for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
- status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Wrap `::android::FrameEventHistoryData` in
@@ -1013,42 +551,9 @@
* native handle. All the non-`nullptr` elements must be deleted individually
* with `native_handle_delete()`.
*/
-inline bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
std::vector<std::vector<native_handle_t*> >* nh,
- ::android::FrameEventHistoryDelta const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ ::android::FrameEventHistoryDelta const& l);
/**
* \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
@@ -1059,42 +564,9 @@
*
* This function will duplicate all file descriptors contained in \p t.
*/
-inline bool convertTo(
+bool convertTo(
::android::FrameEventHistoryDelta* l,
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
// Ref: frameworks/native/libs/ui/Region.cpp
@@ -1104,9 +576,7 @@
* \param[in] t The input `Region`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(Region const& t) {
- return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
-}
+size_t getFlattenedSize(Region const& t);
/**
* \brief Unflatten `Region`.
@@ -1116,36 +586,7 @@
* \param[in,out] size The size of the flat buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t unflatten(Region* t, void const*& buffer, size_t& size) {
- if (size < sizeof(uint32_t)) {
- return NO_MEMORY;
- }
-
- uint32_t numRects = 0;
- FlattenableUtils::read(buffer, size, numRects);
- if (size < numRects * sizeof(Rect)) {
- return NO_MEMORY;
- }
- if (numRects > (UINT32_MAX / sizeof(Rect))) {
- return NO_MEMORY;
- }
-
- t->resize(numRects);
- for (size_t r = 0; r < numRects; ++r) {
- ::android::Rect rect(::android::Rect::EMPTY_RECT);
- status_t status = rect.unflatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- (*t)[r] = Rect{
- static_cast<int32_t>(rect.left),
- static_cast<int32_t>(rect.top),
- static_cast<int32_t>(rect.right),
- static_cast<int32_t>(rect.bottom)};
- }
- return NO_ERROR;
-}
+status_t unflatten(Region* t, void const*& buffer, size_t& size);
/**
* \brief Flatten `Region`.
@@ -1155,26 +596,7 @@
* \param[in,out] size The size of the flat buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t flatten(Region const& t, void*& buffer, size_t& size) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
- for (size_t r = 0; r < t.size(); ++r) {
- ::android::Rect rect(
- static_cast<int32_t>(t[r].left),
- static_cast<int32_t>(t[r].top),
- static_cast<int32_t>(t[r].right),
- static_cast<int32_t>(t[r].bottom));
- status_t status = rect.flatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- }
- return NO_ERROR;
-}
+status_t flatten(Region const& t, void*& buffer, size_t& size);
/**
* \brief Convert `::android::Region` to `Region`.
@@ -1183,28 +605,7 @@
* \param[in] l The source `::android::Region`.
*/
// convert: ::android::Region -> Region
-inline bool convertTo(Region* t, ::android::Region const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (l.flatten(buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (unflatten(t, constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(Region* t, ::android::Region const& l);
/**
* \brief Convert `Region` to `::android::Region`.
@@ -1213,64 +614,19 @@
* \param[in] t The source `Region`.
*/
// convert: Region -> ::android::Region
-inline bool convertTo(::android::Region* l, Region const& t) {
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (flatten(t, buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (l->unflatten(constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(::android::Region* l, Region const& t);
// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
// BGraphicBufferProducer::QueueBufferInput
/**
- * \brief Return a lower bound on the size of the buffer required to flatten
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::QueueBufferInput const& /* t */) {
- return sizeof(int64_t) + // timestamp
- sizeof(int) + // isAutoTimestamp
- sizeof(android_dataspace) + // dataSpace
- sizeof(::android::Rect) + // crop
- sizeof(int) + // scalingMode
- sizeof(uint32_t) + // transform
- sizeof(uint32_t) + // stickyTransform
- sizeof(bool); // getFrameTimestamps
-}
-
-/**
* \brief Return the size of the buffer required to flatten
* `HGraphicBufferProducer::QueueBufferInput`.
*
* \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
- return minFlattenedSize(t) +
- getFenceFlattenedSize(t.fence) +
- getFlattenedSize(t.surfaceDamage) +
- sizeof(HdrMetadata::validTypes);
-}
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -1279,11 +635,8 @@
* \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::QueueBufferInput const& t) {
- return getFenceFdCount(t.fence);
-}
-
+size_t getFdCount(
+ HGraphicBufferProducer::QueueBufferInput const& t);
/**
* \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
*
@@ -1296,40 +649,9 @@
* \return `NO_ERROR` on success; other value on failure.
*
* This function will duplicate the file descriptor in `t.fence`. */
-inline status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
native_handle_t** nh,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.timestamp);
- FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
- FlattenableUtils::write(buffer, size,
- static_cast<android_dataspace_t>(t.dataSpace));
- FlattenableUtils::write(buffer, size, ::android::Rect(
- static_cast<int32_t>(t.crop.left),
- static_cast<int32_t>(t.crop.top),
- static_cast<int32_t>(t.crop.right),
- static_cast<int32_t>(t.crop.bottom)));
- FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
- FlattenableUtils::write(buffer, size, t.transform);
- FlattenableUtils::write(buffer, size, t.stickyTransform);
- FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
-
- *nh = t.fence.getNativeHandle() == nullptr ?
- nullptr : native_handle_clone(t.fence);
- status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- status = flatten(t.surfaceDamage, buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
- return NO_ERROR;
-}
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
@@ -1347,42 +669,9 @@
* descriptor. \p nh needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->timestamp);
- int lIsAutoTimestamp;
- FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
- t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
- android_dataspace_t lDataSpace;
- FlattenableUtils::read(buffer, size, lDataSpace);
- t->dataSpace = static_cast<Dataspace>(lDataSpace);
- Rect lCrop;
- FlattenableUtils::read(buffer, size, lCrop);
- t->crop = Rect{
- static_cast<int32_t>(lCrop.left),
- static_cast<int32_t>(lCrop.top),
- static_cast<int32_t>(lCrop.right),
- static_cast<int32_t>(lCrop.bottom)};
- int lScalingMode;
- FlattenableUtils::read(buffer, size, lScalingMode);
- t->scalingMode = static_cast<int32_t>(lScalingMode);
- FlattenableUtils::read(buffer, size, t->transform);
- FlattenableUtils::read(buffer, size, t->stickyTransform);
- FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
-
- status_t status = unflattenFence(&(t->fence), nh,
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- // HdrMetadata ignored
- return unflatten(&(t->surfaceDamage), buffer, size);
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
@@ -1398,43 +687,10 @@
* descriptor. \p nh needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline bool wrapAs(
+bool wrapAs(
HGraphicBufferProducer::QueueBufferInput* t,
native_handle_t** nh,
- BGraphicBufferProducer::QueueBufferInput const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ BGraphicBufferProducer::QueueBufferInput const& l);
/**
* \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
@@ -1445,48 +701,9 @@
*
* If `t.fence` has a valid file descriptor, it will be duplicated.
*/
-inline bool convertTo(
+bool convertTo(
BGraphicBufferProducer::QueueBufferInput* l,
- HGraphicBufferProducer::QueueBufferInput const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- native_handle_t* nh;
- if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- if (nh != nullptr) {
- native_handle_close(nh);
- native_handle_delete(nh);
- }
- return false;
- }
-
- native_handle_delete(nh);
- return true;
-}
+ HGraphicBufferProducer::QueueBufferInput const& t);
// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
// BGraphicBufferProducer::QueueBufferOutput
@@ -1507,20 +724,9 @@
*/
// wrap: BGraphicBufferProducer::QueueBufferOutput ->
// HGraphicBufferProducer::QueueBufferOutput
-inline bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
std::vector<std::vector<native_handle_t*> >* nh,
- BGraphicBufferProducer::QueueBufferOutput const& l) {
- if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
- return false;
- }
- t->width = l.width;
- t->height = l.height;
- t->transformHint = l.transformHint;
- t->numPendingBuffers = l.numPendingBuffers;
- t->nextFrameNumber = l.nextFrameNumber;
- t->bufferReplaced = l.bufferReplaced;
- return true;
-}
+ BGraphicBufferProducer::QueueBufferOutput const& l);
/**
* \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
@@ -1533,20 +739,9 @@
*/
// convert: HGraphicBufferProducer::QueueBufferOutput ->
// BGraphicBufferProducer::QueueBufferOutput
-inline bool convertTo(
+bool convertTo(
BGraphicBufferProducer::QueueBufferOutput* l,
- HGraphicBufferProducer::QueueBufferOutput const& t) {
- if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
- return false;
- }
- l->width = t.width;
- l->height = t.height;
- l->transformHint = t.transformHint;
- l->numPendingBuffers = t.numPendingBuffers;
- l->nextFrameNumber = t.nextFrameNumber;
- l->bufferReplaced = t.bufferReplaced;
- return true;
-}
+ HGraphicBufferProducer::QueueBufferOutput const& t);
/**
* \brief Convert `BGraphicBufferProducer::DisconnectMode` to
@@ -1555,16 +750,8 @@
* \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
* \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
*/
-inline HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
- BGraphicBufferProducer::DisconnectMode l) {
- switch (l) {
- case BGraphicBufferProducer::DisconnectMode::Api:
- return HGraphicBufferProducer::DisconnectMode::API;
- case BGraphicBufferProducer::DisconnectMode::AllLocal:
- return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
- }
- return HGraphicBufferProducer::DisconnectMode::API;
-}
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l);
/**
* \brief Convert `HGraphicBufferProducer::DisconnectMode` to
@@ -1573,18 +760,10 @@
* \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
* \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
*/
-inline BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
- HGraphicBufferProducer::DisconnectMode t) {
- switch (t) {
- case HGraphicBufferProducer::DisconnectMode::API:
- return BGraphicBufferProducer::DisconnectMode::Api;
- case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
- return BGraphicBufferProducer::DisconnectMode::AllLocal;
- }
- return BGraphicBufferProducer::DisconnectMode::Api;
-}
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+ HGraphicBufferProducer::DisconnectMode t);
} // namespace conversion
} // namespace android
-#endif // MEDIA_STAGEFRIGHT_CONVERSION_H_
+#endif // MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
diff --git a/media/libstagefright/codec2/1.0/Android.bp b/media/libstagefright/codec2/1.0/Android.bp
deleted file mode 100644
index 84d301a..0000000
--- a/media/libstagefright/codec2/1.0/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-cc_library_shared {
- name: "android.hardware.media.c2@1.0-service-impl",
- // relative_install_path: "hw",
- // TODO: vendor: true,
- vendor_available: true,
- vndk: {
- enabled: true,
- },
-
- srcs: [
- //"ComponentAuth.cpp",
- //"Component.cpp",
- //"ComponentListener.cpp",
- //"ComponentStore.cpp",
- //"Configurable.cpp",
- "InputSurface.cpp",
- "InputSurfaceConnection.cpp",
- //"types.cpp",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright/codec2/include",
- "frameworks/av/media/libstagefright/codec2/vndk/internal",
- ],
-
- shared_libs: [
- "libcutils",
- "libgui",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libnativewindow",
- "libstagefright_bufferqueue_helper",
- "libstagefright_codec2_vndk",
- "libui",
- "libutils",
-
- //"android.hardware.media.c2@1.0",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hidl.token@1.0-utils",
- ],
-}
-
diff --git a/media/libstagefright/codec2/1.0/InputSurface.cpp b/media/libstagefright/codec2/1.0/InputSurface.cpp
deleted file mode 100644
index 977d410..0000000
--- a/media/libstagefright/codec2/1.0/InputSurface.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2018, 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 "InputSurface"
-#include <utils/Log.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2PlatformSupport.h>
-
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::GraphicBufferSource;
-
-sp<InputSurface> InputSurface::Create() {
- sp<GraphicBufferSource> source = new GraphicBufferSource;
- if (source->initCheck() != OK) {
- return nullptr;
- }
- return new InputSurface(source->getIGraphicBufferProducer(), source);
-}
-
-InputSurface::InputSurface(
- const sp<BGraphicBufferProducer> &base, const sp<GraphicBufferSource> &source)
- : InputSurfaceBase(base),
- mSource(source) {
-}
-
-sp<InputSurfaceConnection> InputSurface::connectToComponent(
- const std::shared_ptr<C2Component> &comp) {
- sp<InputSurfaceConnection> conn = new InputSurfaceConnection(mSource, comp);
- if (!conn->init()) {
- return nullptr;
- }
- return conn;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp b/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
deleted file mode 100644
index 693eeea..0000000
--- a/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2018, 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 "InputSurfaceConnection"
-#include <utils/Log.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2BlockInternal.h>
-#include <C2PlatformSupport.h>
-
-#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
-#include <system/window.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::status_t;
-
-namespace {
-
-class Buffer2D : public C2Buffer {
-public:
- explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
-};
-
-} // namespace
-
-constexpr int32_t kBufferCount = 16;
-
-class InputSurfaceConnection::Impl : public ComponentWrapper {
-public:
- Impl(const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp)
- : mSource(source), mComp(comp) {
- }
-
- virtual ~Impl() = default;
-
- bool init() {
- sp<GraphicBufferSource> source = mSource.promote();
- if (source == nullptr) {
- return false;
- }
- status_t err = source->initCheck();
- if (err != OK) {
- ALOGE("Impl::init: GBS init failed: %d", err);
- return false;
- }
- // TODO: proper color aspect & dataspace
- android_dataspace dataSpace = HAL_DATASPACE_BT709;
- // TODO: read settings properly from the interface
- err = source->configure(
- this, dataSpace, kBufferCount, 1080, 1920, GRALLOC_USAGE_SW_READ_OFTEN);
- if (err != OK) {
- ALOGE("Impl::init: GBS configure failed: %d", err);
- return false;
- }
- for (int32_t i = 0; i < kBufferCount; ++i) {
- if (!source->onInputBufferAdded(i).isOk()) {
- ALOGE("Impl::init: population GBS slots failed");
- return false;
- }
- }
- if (!source->start().isOk()) {
- ALOGE("Impl::init: GBS start failed");
- return false;
- }
- c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
- C2AllocatorStore::PLATFORM_START + 1, // GRALLOC
- &mAllocator);
- if (c2err != OK) {
- ALOGE("Impl::init: failed to fetch gralloc allocator: %d", c2err);
- return false;
- }
- return true;
- }
-
- // From ComponentWrapper
- status_t submitBuffer(
- int32_t bufferId, const sp<GraphicBuffer> &buffer,
- int64_t timestamp, int fenceFd) override {
- ALOGV("Impl::submitBuffer bufferId = %d", bufferId);
- // TODO: Use fd to construct fence
- (void)fenceFd;
-
- std::shared_ptr<C2Component> comp = mComp.lock();
- if (!comp) {
- return NO_INIT;
- }
-
- std::shared_ptr<C2GraphicAllocation> alloc;
- C2Handle *handle = WrapNativeCodec2GrallocHandle(
- buffer->handle, buffer->width, buffer->height,
- buffer->format, buffer->usage, buffer->stride);
- c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
- if (err != OK) {
- return UNKNOWN_ERROR;
- }
- std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
-
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = (C2FrameData::flags_t)0;
- work->input.ordinal.timestamp = timestamp;
- work->input.ordinal.frameIndex = mFrameIndex++;
- work->input.buffers.clear();
- std::shared_ptr<C2Buffer> c2Buffer(
- // TODO: fence
- new Buffer2D(block->share(
- C2Rect(block->width(), block->height()), ::C2Fence())),
- [handle, bufferId, src = mSource](C2Buffer *ptr) {
- delete ptr;
- native_handle_delete(handle);
- sp<GraphicBufferSource> source = src.promote();
- if (source != nullptr) {
- // TODO: fence
- (void)source->onInputBufferEmptied(bufferId, -1);
- }
- });
- work->input.buffers.push_back(c2Buffer);
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- err = comp->queue_nb(&items);
- if (err != C2_OK) {
- return UNKNOWN_ERROR;
- }
-
- mLastTimestamp = timestamp;
-
- return OK;
- }
-
- status_t submitEos(int32_t) override {
- std::shared_ptr<C2Component> comp = mComp.lock();
- if (!comp) {
- return NO_INIT;
- }
-
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
- work->input.ordinal.timestamp = mLastTimestamp;
- work->input.ordinal.frameIndex = mFrameIndex++;
- work->input.buffers.clear();
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- c2_status_t err = comp->queue_nb(&items);
- return (err == C2_OK) ? OK : UNKNOWN_ERROR;
- }
-
- void dispatchDataSpaceChanged(
- int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
- // TODO
- (void)dataSpace;
- (void)aspects;
- (void)pixelFormat;
- }
-
-private:
- wp<GraphicBufferSource> mSource;
- std::weak_ptr<C2Component> mComp;
-
- // Needed for ComponentWrapper implementation
- int64_t mLastTimestamp;
- std::shared_ptr<C2Allocator> mAllocator;
- std::atomic_uint64_t mFrameIndex;
-};
-
-InputSurfaceConnection::InputSurfaceConnection(
- const sp<GraphicBufferSource> &source,
- const std::shared_ptr<C2Component> &comp)
- : mSource(source),
- mImpl(new Impl(source, comp)) {
-}
-
-InputSurfaceConnection::~InputSurfaceConnection() {
- disconnect();
-}
-
-bool InputSurfaceConnection::init() {
- if (mImpl == nullptr) {
- return false;
- }
- return mImpl->init();
-}
-
-void InputSurfaceConnection::disconnect() {
- ALOGV("disconnect");
- if (mSource != nullptr) {
- (void)mSource->stop();
- (void)mSource->release();
- }
- mImpl.clear();
- mSource.clear();
- ALOGV("disconnected");
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/Android.bp b/media/libstagefright/codec2/Android.bp
deleted file mode 100644
index 1c32953..0000000
--- a/media/libstagefright/codec2/Android.bp
+++ /dev/null
@@ -1,93 +0,0 @@
-cc_library_shared {
- name: "libstagefright_codec2",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
-
- tags: [
- "optional",
- ],
-
- srcs: ["C2.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright/codec2/include",
- "frameworks/native/include/media/hardware",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- header_libs: [
- "libhardware_headers",
- "libutils_headers",
- ],
-
- export_header_lib_headers: [
- "libhardware_headers",
- "libutils_headers",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: false, // true,
- diag: {
- cfi: false, // true,
- },
- },
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-cc_library_shared {
- name: "libstagefright_simple_c2component",
- vendor_available: true,
-
- tags: [
- "optional",
- ],
-
- srcs: [
- "SimpleC2Component.cpp",
- "SimpleC2Interface.cpp",
- ],
-
- include_dirs: [
- ],
-
- shared_libs: [
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libutils",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-subdirs = [
- "tests",
- "vndk",
-]
diff --git a/media/libstagefright/codec2/Android.mk b/media/libstagefright/codec2/Android.mk
deleted file mode 100644
index 459608f..0000000
--- a/media/libstagefright/codec2/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# =============================================================================
-# DOCUMENTATION GENERATION
-# =============================================================================
-C2_ROOT := $(call my-dir)
-
-C2_DOCS_ROOT := $(OUT_DIR)/target/common/docs/codec2
-
-C2_OUT_TEMP := $(PRODUCT_OUT)/gen/ETC/Codec2-docs_intermediates
-
-C2_DOXY := $(or $(shell command -v doxygen),\
- $(shell command -v /Applications/Doxygen.app/Contents/Resources/doxygen))
-
-check-doxygen:
-ifndef C2_DOXY
- $(error 'doxygen is not available')
-endif
-
-$(C2_OUT_TEMP)/doxy-api.config: $(C2_ROOT)/docs/doxygen.config
- # only document include directory, no internal sections
- sed 's/\(^INPUT *=.*\)/\1include\//; \
- s/\(^INTERNAL_DOCS *= *\).*/\1NO/; \
- s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/; \
- s:\(^OUTPUT_DIRECTORY *= \)out:\1'$(OUT_DIR)':;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-$(C2_OUT_TEMP)/doxy-internal.config: $(C2_ROOT)/docs/doxygen.config
- sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$(OUT_DIR)'\2internal:;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-docs-api: $(C2_OUT_TEMP)/doxy-api.config check-doxygen
- echo API docs are building in $(C2_DOCS_ROOT)/api
- rm -rf $(C2_DOCS_ROOT)/api
- mkdir -p $(C2_DOCS_ROOT)/api
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-api.config
-
-docs-internal: $(C2_OUT_TEMP)/doxy-internal.config check-doxygen
- echo Internal docs are building in $(C2_DOCS_ROOT)/internal
- rm -rf $(C2_DOCS_ROOT)/internal
- mkdir -p $(C2_DOCS_ROOT)/internal
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-internal.config
-
-docs-all: docs-api docs-internal
\ No newline at end of file
diff --git a/media/libstagefright/codec2/C2.cpp b/media/libstagefright/codec2/C2.cpp
deleted file mode 100644
index 359d4e5..0000000
--- a/media/libstagefright/codec2/C2.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <C2.h>
-#include <C2Buffer.h>
-#include <C2Component.h>
-#include <C2Config.h>
-#include <C2Param.h>
-#include <C2ParamDef.h>
-#include <C2Work.h>
-
-/**
- * There is nothing here yet. This library is built to see what symbols and methods get
- * defined as part of the API include files.
- *
- * Going forward, the Codec2 library will contain utility methods that are useful for
- * Codec2 clients.
- */
-
-
diff --git a/media/libstagefright/codec2/SimpleC2Component.cpp b/media/libstagefright/codec2/SimpleC2Component.cpp
deleted file mode 100644
index f3d95f6..0000000
--- a/media/libstagefright/codec2/SimpleC2Component.cpp
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2017 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 "SimpleC2Component"
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <inttypes.h>
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Component.h>
-
-namespace android {
-
-std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
- std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
- mQueue.pop_front();
- return work;
-}
-
-void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
- mQueue.push_back({ std::move(work), NO_DRAIN });
-}
-
-bool SimpleC2Component::WorkQueue::empty() const {
- return mQueue.empty();
-}
-
-void SimpleC2Component::WorkQueue::clear() {
- mQueue.clear();
-}
-
-uint32_t SimpleC2Component::WorkQueue::drainMode() const {
- return mQueue.front().drainMode;
-}
-
-void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
- mQueue.push_back({ nullptr, drainMode });
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-SimpleC2Component::SimpleC2Component(
- const std::shared_ptr<C2ComponentInterface> &intf)
- : mIntf(intf) {
-}
-
-c2_status_t SimpleC2Component::setListener_vb(
- const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState == RUNNING) {
- if (listener) {
- return C2_BAD_STATE;
- } else if (!mayBlock) {
- return C2_BLOCKING;
- }
- }
- state->mListener = listener;
- // TODO: wait for listener change to have taken place before returning
- // (e.g. if there is an ongoing listener callback)
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
- {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState != RUNNING) {
- return C2_BAD_STATE;
- }
- }
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- while (!items->empty()) {
- queue->push_back(std::move(items->front()));
- items->pop_front();
- }
- queue->mCondition.broadcast();
- }
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
- (void)items;
- return C2_OMITTED;
-}
-
-c2_status_t SimpleC2Component::flush_sm(
- flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
- (void)flushMode;
- {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState != RUNNING) {
- return C2_BAD_STATE;
- }
- }
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- queue->incGeneration();
- // TODO: queue->splicedBy(flushedWork, flushedWork->end());
- while (!queue->empty()) {
- std::unique_ptr<C2Work> work = queue->pop_front();
- if (work) {
- flushedWork->push_back(std::move(work));
- }
- }
- }
- {
- Mutexed<PendingWork>::Locked pending(mPendingWork);
- while (!pending->empty()) {
- flushedWork->push_back(std::move(pending->begin()->second));
- pending->erase(pending->begin());
- }
- }
-
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
- if (drainMode == DRAIN_CHAIN) {
- return C2_OMITTED;
- }
- {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState != RUNNING) {
- return C2_BAD_STATE;
- }
- }
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- queue->markDrain(drainMode);
- queue->mCondition.broadcast();
- }
-
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::start() {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState == RUNNING) {
- return C2_BAD_STATE;
- }
- bool needsInit = (state->mState == UNINITIALIZED);
- if (needsInit) {
- state.unlock();
- c2_status_t err = onInit();
- if (err != C2_OK) {
- return err;
- }
- state.lock();
- }
- if (!state->mThread.joinable()) {
- mExitRequested = false;
- {
- Mutexed<ExitMonitor>::Locked monitor(mExitMonitor);
- monitor->mExited = false;
- }
- state->mThread = std::thread(
- [](std::weak_ptr<SimpleC2Component> wp) {
- while (true) {
- std::shared_ptr<SimpleC2Component> thiz = wp.lock();
- if (!thiz) {
- return;
- }
- if (thiz->exitRequested()) {
- ALOGV("stop processing");
- thiz->signalExit();
- return;
- }
- thiz->processQueue();
- }
- },
- shared_from_this());
- }
- state->mState = RUNNING;
- return C2_OK;
-}
-
-void SimpleC2Component::signalExit() {
- Mutexed<ExitMonitor>::Locked monitor(mExitMonitor);
- monitor->mExited = true;
- monitor->mCondition.broadcast();
-}
-
-void SimpleC2Component::requestExitAndWait(std::function<void()> job) {
- {
- Mutexed<ExecState>::Locked state(mExecState);
- if (!state->mThread.joinable()) {
- return;
- }
- }
- mExitRequested = true;
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- queue->mCondition.broadcast();
- }
- // TODO: timeout?
- {
- Mutexed<ExitMonitor>::Locked monitor(mExitMonitor);
- while (!monitor->mExited) {
- monitor.waitForCondition(monitor->mCondition);
- }
- job();
- }
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mThread.joinable()) {
- ALOGV("joining the processing thread");
- state->mThread.join();
- ALOGV("joined the processing thread");
- }
-}
-
-c2_status_t SimpleC2Component::stop() {
- ALOGV("stop");
- {
- Mutexed<ExecState>::Locked state(mExecState);
- if (state->mState != RUNNING) {
- return C2_BAD_STATE;
- }
- state->mState = STOPPED;
- }
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- queue->clear();
- }
- {
- Mutexed<PendingWork>::Locked pending(mPendingWork);
- pending->clear();
- }
- c2_status_t err;
- requestExitAndWait([this, &err]{ err = onStop(); });
- if (err != C2_OK) {
- return err;
- }
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::reset() {
- ALOGV("reset");
- {
- Mutexed<ExecState>::Locked state(mExecState);
- state->mState = UNINITIALIZED;
- }
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- queue->clear();
- }
- {
- Mutexed<PendingWork>::Locked pending(mPendingWork);
- pending->clear();
- }
- requestExitAndWait([this]{ onReset(); });
- return C2_OK;
-}
-
-c2_status_t SimpleC2Component::release() {
- ALOGV("release");
- requestExitAndWait([this]{ onRelease(); });
- return C2_OK;
-}
-
-std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
- return mIntf;
-}
-
-namespace {
-
-std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
- std::list<std::unique_ptr<C2Work>> ret;
- ret.push_back(std::move(work));
- return ret;
-}
-
-} // namespace
-
-void SimpleC2Component::finish(
- uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
- std::unique_ptr<C2Work> work;
- {
- Mutexed<PendingWork>::Locked pending(mPendingWork);
- if (pending->count(frameIndex) == 0) {
- ALOGW("unknown frame index: %" PRIu64, frameIndex);
- return;
- }
- work = std::move(pending->at(frameIndex));
- pending->erase(frameIndex);
- }
- if (work) {
- fillWork(work);
- Mutexed<ExecState>::Locked state(mExecState);
- state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
- ALOGV("returning pending work");
- }
-}
-
-void SimpleC2Component::processQueue() {
- std::unique_ptr<C2Work> work;
- uint64_t generation;
- int32_t drainMode;
- bool isFlushPending = false;
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- nsecs_t deadline = systemTime() + ms2ns(250);
- while (queue->empty()) {
- if (exitRequested()) {
- return;
- }
- nsecs_t now = systemTime();
- if (now >= deadline) {
- return;
- }
- status_t err = queue.waitForConditionRelative(queue->mCondition, deadline - now);
- if (err == TIMED_OUT) {
- return;
- }
- }
-
- generation = queue->generation();
- drainMode = queue->drainMode();
- isFlushPending = queue->popPendingFlush();
- work = queue->pop_front();
- }
- if (isFlushPending) {
- ALOGV("processing pending flush");
- c2_status_t err = onFlush_sm();
- if (err != C2_OK) {
- ALOGD("flush err: %d", err);
- // TODO: error
- }
- }
-
- if (!mOutputBlockPool) {
- c2_status_t err = [this] {
- // TODO: don't use query_vb
- C2StreamFormatConfig::output outputFormat(0u);
- c2_status_t err = intf()->query_vb(
- { &outputFormat },
- {},
- C2_DONT_BLOCK,
- nullptr);
- if (err != C2_OK) {
- return err;
- }
- if (outputFormat.value == C2FormatVideo) {
- err = GetCodec2BlockPool(
- C2BlockPool::BASIC_GRAPHIC,
- shared_from_this(), &mOutputBlockPool);
- } else {
- err = CreateCodec2BlockPool(
- C2PlatformAllocatorStore::ION,
- shared_from_this(), &mOutputBlockPool);
- }
- if (err != C2_OK) {
- return err;
- }
- return C2_OK;
- }();
- if (err != C2_OK) {
- Mutexed<ExecState>::Locked state(mExecState);
- state->mListener->onError_nb(shared_from_this(), err);
- return;
- }
- }
-
- if (!work) {
- c2_status_t err = drain(drainMode, mOutputBlockPool);
- if (err != C2_OK) {
- Mutexed<ExecState>::Locked state(mExecState);
- state->mListener->onError_nb(shared_from_this(), err);
- }
- return;
- }
-
- process(work, mOutputBlockPool);
- ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
- {
- Mutexed<WorkQueue>::Locked queue(mWorkQueue);
- if (queue->generation() != generation) {
- ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
- queue->generation(), generation);
- work->result = C2_NOT_FOUND;
- queue.unlock();
- {
- Mutexed<ExecState>::Locked state(mExecState);
- state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
- }
- queue.lock();
- return;
- }
- }
- if (work->workletsProcessed != 0u) {
- Mutexed<ExecState>::Locked state(mExecState);
- ALOGV("returning this work");
- state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
- } else {
- ALOGV("queue pending work");
- std::unique_ptr<C2Work> unexpected;
- {
- Mutexed<PendingWork>::Locked pending(mPendingWork);
- uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
- if (pending->count(frameIndex) != 0) {
- unexpected = std::move(pending->at(frameIndex));
- pending->erase(frameIndex);
- }
- (void)pending->insert({ frameIndex, std::move(work) });
- }
- if (unexpected) {
- ALOGD("unexpected pending work");
- unexpected->result = C2_CORRUPTED;
- Mutexed<ExecState>::Locked state(mExecState);
- state->mListener->onWorkDone_nb(shared_from_this(), vec(unexpected));
- }
- }
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
- const std::shared_ptr<C2LinearBlock> &block) {
- return createLinearBuffer(block, block->offset(), block->size());
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
- const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
- return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
- const std::shared_ptr<C2GraphicBlock> &block) {
- return createGraphicBuffer(block, C2Rect(0, 0, block->width(), block->height()));
-}
-
-std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
- const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
- return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/SimpleC2Interface.cpp b/media/libstagefright/codec2/SimpleC2Interface.cpp
deleted file mode 100644
index d159426..0000000
--- a/media/libstagefright/codec2/SimpleC2Interface.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 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 "SimpleC2Interface"
-#include <utils/Log.h>
-
-#include <SimpleC2Interface.h>
-
-namespace android {
-
-c2_status_t SimpleC2Interface::query_vb(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
- (void)mayBlock;
-
- for (C2Param* const param : stackParams) {
- if (param->coreIndex() != C2StreamFormatConfig::CORE_INDEX
- || !param->forStream()
- || param->stream() != 0u) {
- param->invalidate();
- continue;
- }
- if (param->forInput()) {
- param->updateFrom(mInputFormat);
- } else {
- param->updateFrom(mOutputFormat);
- }
- }
- if (heapParams) {
- heapParams->clear();
- for (const auto &index : heapParamIndices) {
- switch (index.type()) {
- case C2StreamFormatConfig::input::PARAM_TYPE:
- if (index.stream() == 0u) {
- heapParams->push_back(C2Param::Copy(mInputFormat));
- } else {
- heapParams->push_back(nullptr);
- }
- break;
- case C2StreamFormatConfig::output::PARAM_TYPE:
- if (index.stream() == 0u) {
- heapParams->push_back(C2Param::Copy(mOutputFormat));
- } else {
- heapParams->push_back(nullptr);
- }
- break;
- case C2PortMimeConfig::input::PARAM_TYPE:
- if (mInputMediaType) {
- heapParams->push_back(C2Param::Copy(*mInputMediaType));
- } else {
- heapParams->push_back(nullptr);
- }
- break;
- case C2PortMimeConfig::output::PARAM_TYPE:
- if (mOutputMediaType) {
- heapParams->push_back(C2Param::Copy(*mOutputMediaType));
- } else {
- heapParams->push_back(nullptr);
- }
- break;
- default:
- heapParams->push_back(nullptr);
- break;
- }
- }
- }
-
- return C2_OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/client/Android.bp b/media/libstagefright/codec2/client/Android.bp
deleted file mode 100644
index 0129e15..0000000
--- a/media/libstagefright/codec2/client/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-cc_library {
- name: "libstagefright_codec2_client",
-
- srcs: [
- "client.cpp",
- ],
-
- shared_libs: [
- "android.hardware.media.bufferpool@1.0",
- "libcutils",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_codec2_hidl@1.0",
- "libutils",
- "vendor.google.media.c2@1.0",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- export_shared_lib_headers: [
- "libstagefright_codec2",
- ],
-
-}
-
diff --git a/media/libstagefright/codec2/client/client.cpp b/media/libstagefright/codec2/client/client.cpp
deleted file mode 100644
index 5a176dc..0000000
--- a/media/libstagefright/codec2/client/client.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2Client-interfaces"
-#include <log/log.h>
-
-#include <media/stagefright/codec2/client.h>
-
-#include <codec2/hidl/1.0/types.h>
-
-#include <vendor/google/media/c2/1.0/IComponentListener.h>
-#include <vendor/google/media/c2/1.0/IConfigurable.h>
-#include <vendor/google/media/c2/1.0/IComponentInterface.h>
-#include <vendor/google/media/c2/1.0/IComponent.h>
-#include <vendor/google/media/c2/1.0/IComponentStore.h>
-
-#include <hidl/HidlSupport.h>
-
-#include <limits>
-#include <type_traits>
-
-namespace /* unnamed */ {
-
-// TODO: Find the appropriate error code for this
-constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
-
-} // unnamed namespace
-
-namespace android {
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-using namespace ::vendor::google::media::c2::V1_0;
-using namespace ::vendor::google::media::c2::V1_0::implementation;
-
-// Codec2ConfigurableClient
-
-const C2String& Codec2ConfigurableClient::getName() const {
- return mName;
-}
-
-Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
-Codec2ConfigurableClient::Codec2ConfigurableClient(
- const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
- Return<void> transStatus = base->getName(
- [this](const hidl_string& name) {
- mName = name.c_str();
- });
- if (!transStatus.isOk()) {
- ALOGE("Cannot obtain name from IConfigurable.");
- }
-}
-
-c2_status_t Codec2ConfigurableClient::query(
- const std::vector<C2Param::Index> &indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const {
- hidl_vec<ParamIndex> hidlIndices(indices.size());
- size_t i = 0;
- for (const C2Param::Index& index : indices) {
- hidlIndices[i++] = static_cast<ParamIndex>(index.operator uint32_t());
- }
- c2_status_t status;
- Return<void> transStatus = base()->query(
- hidlIndices,
- mayBlock == C2_MAY_BLOCK,
- [&status, params](Status s, const Params& p) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- status = copyParamsFromBlob(params, p);
- });
- if (!transStatus.isOk()) {
- ALOGE("query -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-c2_status_t Codec2ConfigurableClient::config(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
- Params hidlParams;
- Status hidlStatus = createParamsBlob(&hidlParams, params);
- if (hidlStatus != Status::OK) {
- ALOGE("config -- bad input.");
- return C2_TRANSACTION_FAILED;
- }
- c2_status_t status;
- Return<void> transStatus = base()->config(
- hidlParams,
- mayBlock == C2_MAY_BLOCK,
- [&status, ¶ms, failures](
- Status s,
- const hidl_vec<SettingResult> f,
- const Params& o) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- failures->clear();
- failures->resize(f.size());
- size_t i = 0;
- for (const SettingResult& sf : f) {
- status = objcpy(&(*failures)[i++], sf);
- if (status != C2_OK) {
- return;
- }
- }
- status = updateParamsFromBlob(params, o);
- });
- if (!transStatus.isOk()) {
- ALOGE("config -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-c2_status_t Codec2ConfigurableClient::querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
- // TODO: Cache and query properly!
- c2_status_t status;
- Return<void> transStatus = base()->querySupportedParams(
- std::numeric_limits<uint32_t>::min(),
- std::numeric_limits<uint32_t>::max(),
- [&status, params](
- Status s,
- const hidl_vec<ParamDescriptor>& p) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- params->resize(p.size());
- size_t i = 0;
- for (const ParamDescriptor& sp : p) {
- status = objcpy(&(*params)[i++], sp);
- if (status != C2_OK) {
- return;
- }
- }
- });
- if (!transStatus.isOk()) {
- ALOGE("querySupportedParams -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-c2_status_t Codec2ConfigurableClient::querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields,
- c2_blocking_t mayBlock) const {
- hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
- for (size_t i = 0; i < fields.size(); ++i) {
- Status hidlStatus = objcpy(&inFields[i], fields[i]);
- if (hidlStatus != Status::OK) {
- ALOGE("querySupportedValues -- bad input");
- return C2_TRANSACTION_FAILED;
- }
- }
-
- c2_status_t status;
- Return<void> transStatus = base()->querySupportedValues(
- inFields,
- mayBlock == C2_MAY_BLOCK,
- [&status, &inFields, &fields](
- Status s,
- const hidl_vec<FieldSupportedValuesQueryResult>& r) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- if (r.size() != fields.size()) {
- ALOGE("querySupportedValues -- input and output lists "
- "have different sizes.");
- status = C2_CORRUPTED;
- return;
- }
- for (size_t i = 0; i < fields.size(); ++i) {
- status = objcpy(&fields[i], inFields[i], r[i]);
- if (status != C2_OK) {
- return;
- }
- }
- });
- if (!transStatus.isOk()) {
- ALOGE("querySupportedValues -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-// Codec2Client
-
-Codec2Client::Base* Codec2Client::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base) :
- Codec2ConfigurableClient(base), mListed(false) {
-}
-
-c2_status_t Codec2Client::createComponent(
- const C2String& name,
- const std::shared_ptr<Codec2Client::Listener>& listener,
- std::shared_ptr<Codec2Client::Component>* const component) {
-
- // TODO: Add support for Bufferpool
-
- struct HidlListener : public IComponentListener {
- std::shared_ptr<Codec2Client::Listener> base;
- std::weak_ptr<Codec2Client::Component> component;
-
- virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
- std::list<std::unique_ptr<C2Work>> workItems;
- c2_status_t status = objcpy(&workItems, workBundle);
- if (status != C2_OK) {
- ALOGE("onWorkDone -- received corrupted WorkBundle. "
- "Error code: %d", static_cast<int>(status));
- return Void();
- }
- base->onWorkDone(component, workItems);
- return Void();
- }
-
- virtual Return<void> onTripped(
- const hidl_vec<SettingResult>& settingResults) override {
- std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
- settingResults.size());
- c2_status_t status;
- for (size_t i = 0; i < settingResults.size(); ++i) {
- std::unique_ptr<C2SettingResult> c2SettingResult;
- status = objcpy(&c2SettingResult, settingResults[i]);
- if (status != C2_OK) {
- ALOGE("onTripped -- received corrupted SettingResult. "
- "Error code: %d", static_cast<int>(status));
- return Void();
- }
- c2SettingResults[i] = std::move(c2SettingResult);
- }
- base->onTripped(component, c2SettingResults);
- return Void();
- }
-
- virtual Return<void> onError(Status s, uint32_t errorCode) override {
- base->onError(component, s == Status::OK ?
- errorCode : static_cast<c2_status_t>(s));
- return Void();
- }
- };
-
- c2_status_t status;
- sp<HidlListener> hidlListener = new HidlListener();
- hidlListener->base = listener;
- Return<void> transStatus = base()->createComponent(
- name,
- hidlListener,
- nullptr,
- [&status, component](
- Status s,
- const sp<IComponent>& c) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- *component = std::make_shared<Codec2Client::Component>(c);
- });
- if (!transStatus.isOk()) {
- ALOGE("createComponent -- failed transaction.");
- return C2_TRANSACTION_FAILED;
- }
- if (status != C2_OK) {
- ALOGE("createComponent -- failed to create component.");
- return status;
- }
- hidlListener->component = *component;
- return status;
-}
-
-c2_status_t Codec2Client::createInterface(
- const C2String& name,
- std::shared_ptr<Codec2Client::Interface>* const interface) {
- c2_status_t status;
- Return<void> transStatus = base()->createInterface(
- name,
- [&status, interface](
- Status s,
- const sp<IComponentInterface>& i) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- *interface = std::make_shared<Codec2Client::Interface>(i);
- });
- if (!transStatus.isOk()) {
- ALOGE("createInterface -- failed transaction.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-const std::vector<C2Component::Traits>& Codec2Client::listComponents()
- const {
- if (mListed) {
- return mTraitsList;
- }
- Return<void> transStatus = base()->listComponents(
- [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
- mTraitsList.resize(t.size());
- mAliasesBuffer.resize(t.size());
- for (size_t i = 0; i < t.size(); ++i) {
- c2_status_t status = objcpy(
- &mTraitsList[i], &mAliasesBuffer[i], t[i]);
- if (status != C2_OK) {
- ALOGE("listComponents -- corrupted output.");
- return;
- }
- }
- });
- if (!transStatus.isOk()) {
- ALOGE("listComponents -- failed transaction.");
- }
- mListed = true;
- return mTraitsList;
-}
-
-c2_status_t Codec2Client::copyBuffer(
- const std::shared_ptr<C2Buffer>& src,
- const std::shared_ptr<C2Buffer>& dst) {
- // TODO: Implement?
- (void)src;
- (void)dst;
- ALOGE("copyBuffer not implemented");
- return C2_OMITTED;
-}
-
-std::shared_ptr<C2ParamReflector>
- Codec2Client::getParamReflector() {
- // TODO: Implement this once there is a way to construct C2StructDescriptor
- // dynamically.
- ALOGE("getParamReflector -- not implemented.");
- return nullptr;
-}
-
-std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
- const char* instanceName, bool waitForService) {
- sp<Base> baseStore = waitForService ?
- Base::getService(instanceName) :
- Base::tryGetService(instanceName);
- if (!baseStore) {
- if (waitForService) {
- ALOGE("Codec2.0 service inaccessible. Check the device manifest.");
- } else {
- ALOGW("Codec2.0 service not available right now. Try again later.");
- }
- return nullptr;
- }
- return std::make_shared<Codec2Client>(baseStore);
-}
-
-// Codec2Client::Listener
-
-Codec2Client::Listener::~Listener() {
-}
-
-// Codec2Client::Component
-
-Codec2Client::Component::Base* Codec2Client::Component::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
- Codec2Client::Configurable(base) {
-}
-
-c2_status_t Codec2Client::Component::createBlockPool(
- C2Allocator::id_t id,
- C2BlockPool::local_id_t* localId,
- std::shared_ptr<Codec2Client::Configurable>* configurable) {
- c2_status_t status;
- Return<void> transStatus = base()->createBlockPool(
- static_cast<uint32_t>(id),
- [&status, localId, configurable](
- Status s,
- uint64_t pId,
- const sp<IConfigurable>& c) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- *localId = static_cast<C2BlockPool::local_id_t>(pId);
- *configurable = std::make_shared<Codec2Client::Configurable>(c);
- });
- if (!transStatus.isOk()) {
- ALOGE("createBlockPool -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-c2_status_t Codec2Client::Component::queue(
- std::list<std::unique_ptr<C2Work>>* const items) {
- WorkBundle workBundle;
- Status hidlStatus = objcpy(&workBundle, *items);
- if (hidlStatus != Status::OK) {
- ALOGE("queue -- bad input.");
- return C2_TRANSACTION_FAILED;
- }
- Return<Status> transStatus = base()->queue(workBundle);
- if (!transStatus.isOk()) {
- ALOGE("queue -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-c2_status_t Codec2Client::Component::flush(
- C2Component::flush_mode_t mode,
- std::list<std::unique_ptr<C2Work>>* const flushedWork) {
- (void)mode; // Flush mode isn't supported in HIDL yet.
- c2_status_t status;
- Return<void> transStatus = base()->flush(
- [&status, flushedWork](
- Status s, const WorkBundle& wb) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- return;
- }
- status = objcpy(flushedWork, wb);
- });
- if (!transStatus.isOk()) {
- ALOGE("flush -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
- Return<Status> transStatus = base()->drain(
- mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
- if (!transStatus.isOk()) {
- ALOGE("drain -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-c2_status_t Codec2Client::Component::start() {
- Return<Status> transStatus = base()->start();
- if (!transStatus.isOk()) {
- ALOGE("start -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-c2_status_t Codec2Client::Component::stop() {
- Return<Status> transStatus = base()->stop();
- if (!transStatus.isOk()) {
- ALOGE("stop -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-c2_status_t Codec2Client::Component::reset() {
- Return<Status> transStatus = base()->reset();
- if (!transStatus.isOk()) {
- ALOGE("reset -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-c2_status_t Codec2Client::Component::release() {
- Return<Status> transStatus = base()->release();
- if (!transStatus.isOk()) {
- ALOGE("release -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return static_cast<c2_status_t>(static_cast<Status>(transStatus));
-}
-
-
-
-
-} // namespace android
-
diff --git a/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h b/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h
deleted file mode 100644
index 1bbf459..0000000
--- a/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef CODEC2_CLIENT_INTERFACES_H_
-#define CODEC2_CLIENT_INTERFACES_H_
-
-#include <C2Component.h>
-#include <C2Buffer.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <utils/StrongPointer.h>
-
-#include <memory>
-
-/**
- * This file contains minimal interfaces for the framework to access Codec2.0.
- *
- * Codec2Client is the main class that contains the following inner classes:
- * - Listener
- * - Configurable
- * - Interface
- * - Component
- *
- * Classes in Codec2Client, interfaces in Codec2.0, and HIDL interfaces are
- * related as follows:
- * - Codec2Client <==> C2ComponentStore <==> IComponentStore
- * - Codec2Client::Listener <==> C2Component::Listener <==> IComponentListener
- * - Codec2Client::Configurable <==> [No equivalent] <==> IConfigurable
- * - Codec2Client::Interface <==> C2ComponentInterface <==> IComponentInterface
- * - Codec2Client::Component <==> C2Component <==> IComponent
- *
- * The entry point is Codec2Client::CreateFromService(), which creates a
- * Codec2Client object. From Codec2Client, Interface and Component objects can
- * be created by calling createComponent() and createInterface().
- *
- * createComponent() takes a Listener object, which must be implemented by the
- * user.
- *
- * At the present, createBlockPool() is the only method that yields a
- * Configurable object. Note, however, that Interface, Component and
- * Codec2Client are all subclasses of Configurable.
- */
-
-// Forward declaration of HIDL interfaces
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-struct IConfigurable;
-struct IComponentInterface;
-struct IComponent;
-struct IComponentStore;
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-namespace android {
-
-// This class is supposed to be called Codec2Client::Configurable, but forward
-// declaration of an inner class is not possible.
-struct Codec2ConfigurableClient {
-
- typedef ::vendor::google::media::c2::V1_0::IConfigurable Base;
-
- const C2String& getName() const;
-
- c2_status_t query(
- const std::vector<C2Param::Index> &indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const;
-
- c2_status_t config(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures
- );
-
- c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
- ) const;
-
- c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields,
- c2_blocking_t mayBlock) const;
-
- // base cannot be null.
- Codec2ConfigurableClient(const sp<Base>& base);
-
-protected:
- C2String mName;
- sp<Base> mBase;
-
- Base* base() const;
-
- friend struct Codec2Client;
-};
-
-struct Codec2Client : public Codec2ConfigurableClient {
-
- typedef ::vendor::google::media::c2::V1_0::IComponentStore Base;
-
- struct Listener;
-
- typedef Codec2ConfigurableClient Configurable;
-
- typedef Configurable Interface; // These two types may diverge in the future.
-
- struct Component;
-
- typedef Codec2Client Store;
-
- c2_status_t createComponent(
- const C2String& name,
- const std::shared_ptr<Listener>& listener,
- std::shared_ptr<Component>* const component);
-
- c2_status_t createInterface(
- const C2String& name,
- std::shared_ptr<Interface>* const interface);
-
- const std::vector<C2Component::Traits>&
- listComponents() const;
-
- c2_status_t copyBuffer(
- const std::shared_ptr<C2Buffer>& src,
- const std::shared_ptr<C2Buffer>& dst);
-
- std::shared_ptr<C2ParamReflector> getParamReflector();
-
- static std::shared_ptr<Codec2Client> CreateFromService(
- const char* instanceName,
- bool waitForService = true);
-
- // base cannot be null.
- Codec2Client(const sp<Base>& base);
-
-protected:
- mutable bool mListed;
- mutable std::vector<C2Component::Traits> mTraitsList;
- mutable std::vector<std::unique_ptr<std::vector<std::string>>>
- mAliasesBuffer;
-
- Base* base() const;
-};
-
-struct Codec2Client::Listener {
-
- virtual void onWorkDone(
- const std::weak_ptr<Codec2Client::Component>& comp,
- const std::list<std::unique_ptr<C2Work>>& workItems) = 0;
-
- virtual void onTripped(
- const std::weak_ptr<Codec2Client::Component>& comp,
- const std::vector<std::shared_ptr<C2SettingResult>>& settingResults
- ) = 0;
-
- virtual void onError(
- const std::weak_ptr<Codec2Client::Component>& comp,
- uint32_t errorCode) = 0;
-
- virtual ~Listener();
-
-};
-
-struct Codec2Client::Component : public Codec2Client::Configurable {
-
- typedef ::vendor::google::media::c2::V1_0::IComponent Base;
-
- c2_status_t createBlockPool(
- C2Allocator::id_t id,
- C2BlockPool::local_id_t* localId,
- std::shared_ptr<Codec2Client::Configurable>* configurable);
-
- c2_status_t queue(
- std::list<std::unique_ptr<C2Work>>* const items);
-
- c2_status_t flush(
- C2Component::flush_mode_t mode,
- std::list<std::unique_ptr<C2Work>>* const flushedWork);
-
- c2_status_t drain(C2Component::drain_mode_t mode);
-
- c2_status_t start();
-
- c2_status_t stop();
-
- c2_status_t reset();
-
- c2_status_t release();
-
- // base cannot be null.
- Component(const sp<Base>& base);
-
-protected:
- Base* base() const;
-
- friend struct Codec2Client;
-};
-
-} // namespace android
-
-#endif // CODEC2_CLIENT_INTERFACES_H_
-
diff --git a/media/libstagefright/codec2/docs/doxyfilter.sh b/media/libstagefright/codec2/docs/doxyfilter.sh
deleted file mode 100755
index d813153..0000000
--- a/media/libstagefright/codec2/docs/doxyfilter.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python3
-import re, sys
-
-global in_comment, current, indent, hold
-in_comment, current, indent, hold = False, None, '', []
-
-class ChangeCStyleCommentsToDoxy:
- def dump_hold():
- global hold
- for h in hold:
- print(h, end='')
- hold[:] = []
-
- def doxy_hold():
- global current, hold
- if current == '//':
- for h in hold:
- print(re.sub(r'^( *//(?!/))', r'\1/', h), end='')
- else:
- first = True
- for h in hold:
- if first:
- h = re.sub(r'^( */[*](?![*]))', r'\1*', h)
- first = False
- print(h, end='')
- hold[:] = []
-
- def process_comment(t, ind, line):
- global current, indent, hold
- if t != current or ind not in (indent, indent + ' '):
- dump_hold()
- current, indent = t, ind
- hold.append(line)
-
- def process_line(ind, line):
- global current, indent
- if ind in (indent, ''):
- doxy_hold()
- else:
- dump_hold()
- current, indent = None, None
- print(line, end='')
-
- def process(self, input, path):
- for line in input:
- ind = re.match(r'^( *)', line).group(1)
- if in_comment:
- # TODO: this is not quite right, but good enough
- m = re.match(r'^ *[*]/', line)
- if m:
- process_comment('/*', ind, line)
- in_comment = False
- else:
- process_comment('/*', ind, line)
- continue
- m = re.match(r'^ *//', line)
- if m:
- # one-line comment
- process_comment('//', ind, line)
- continue
- m = re.match(r'^ */[*]', line)
- if m:
- # multi-line comment
- process_comment('/*', ind, line)
- # TODO: this is not quite right, but good enough
- in_comment = not re.match(r'^ *[*]/', line)
- continue
- process_line(ind, line)
-
-class AutoGroup:
- def process(self, input, path):
- if '/codec2/include/' in path:
- group = 'API Codec2 API'
- elif False:
- return
- elif '/codec2/vndk/' in path:
- group = 'VNDK Platform provided glue'
- elif '/codec2/tests/' in path:
- group = 'Tests Unit tests'
- else:
- group = 'Random Misc. sandbox'
-
- print('#undef __APPLE__')
-
- for line in input:
- if re.match(r'^namespace android {', line):
- print(line, end='')
- print()
- print(r'/// \addtogroup {}'.format(group))
- print(r'/// @{')
- continue
- elif re.match(r'^} +// +namespace', line):
- print(r'/// @}')
- print()
- print(line, end='')
-
-P = AutoGroup()
-for path in sys.argv[1:]:
- with open(path, 'rt') as input:
- P.process(input, path)
diff --git a/media/libstagefright/codec2/docs/doxygen.config b/media/libstagefright/codec2/docs/doxygen.config
deleted file mode 100644
index 11a921f..0000000
--- a/media/libstagefright/codec2/docs/doxygen.config
+++ /dev/null
@@ -1,2446 +0,0 @@
-# Doxyfile 1.8.11
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME = Codec2
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF =
-
-# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
-# in the documentation. The maximum height of the logo should not exceed 55
-# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
-# the logo to the output directory.
-
-PROJECT_LOGO =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = out/target/common/docs/codec2/api
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB = YES
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH = frameworks/av/media/libstagefright/codec2
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF = YES
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
-# page for each member. If set to NO, the documentation of a member will be part
-# of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT = YES
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# If one adds a struct or class to a group and this option is enabled, then also
-# any nested class or struct is added to the same group. By default this option
-# is disabled and one has to add nested compounds explicitly via \ingroup.
-# The default value is: NO.
-
-GROUP_NESTED_COMPOUNDS = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT = YES
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS = YES
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES = YES
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
-# list. This list is created by putting \todo commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS = INTERNAL
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC = NO
-
-# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered.
-# The default value is: NO.
-
-WARN_AS_ERROR = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
-# Note: If this tag is empty the current directory is searched.
-
-INPUT = frameworks/av/media/libstagefright/codec2/
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# read by doxygen.
-#
-# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
-# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
-# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
-# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
-
-FILE_PATTERNS = C2*.c \
- C2*.cpp \
- C2*.h
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS = ._*
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-INPUT_FILTER = frameworks/av/media/libstagefright/codec2/docs/doxyfilter.sh
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES = YES
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION = YES
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
-# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
-# cost of reduced performance. This can be particularly helpful with template
-# rich C++ code for which doxygen's built-in parser lacks the necessary type
-# information.
-# Note: The availability of this option depends on whether or not doxygen was
-# generated with the -Duse-libclang=ON option for CMake.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = YES
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS = -std=c++11
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS = YES
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW = YES
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. The package can be specified just
-# by its name or with the correct syntax as to be used with the LaTeX
-# \usepackage command. To get the times font for instance you can specify :
-# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
-# To use the option intlimits with the amsmath package you can specify:
-# EXTRA_PACKAGES=[intlimits]{amsmath}
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER =
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE = plain
-
-# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_TIMESTAMP = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE =
-
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF = YES
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH = /Volumes/A/aosp/prebuilts/clang/darwin-x86/host/3.6/lib/clang/3.6/include \
- /Volumes/A/aosp/external/libcxx/include \
- /Volumes/A/aosp/bionic/libc/include \
- /Volumes/A/aosp/bionic/libc/kernel/uapi \
- /Volumes/A/aosp/bionic/libc/kernel/uapi/asm-arm64 \
- /Volumes/A/aosp/external/gtest
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED = __APPLE__= \
- __ANDROID__=1 \
- ANDROID:=1 \
- __unused=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED = DEFINE_FLEXIBLE_METHODS \
- DEFINE_CAST_OPERATORS
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
-# The default value is: NO.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH =
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command. Disabling a call graph can be
-# accomplished by means of the command \hidecallgraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command. Disabling a caller graph can be
-# accomplished by means of the command \hidecallergraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. For an explanation of the image formats see the section
-# output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
-# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
-# png:gdiplus:gdiplus.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS =
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-
-PLANTUML_JAR_PATH =
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP = YES
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Android.bp b/media/libstagefright/codec2/hidl/impl/1.0/Android.bp
deleted file mode 100644
index 3d930c6..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/Android.bp
+++ /dev/null
@@ -1,42 +0,0 @@
-cc_library {
- name: "libstagefright_codec2_hidl@1.0",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
-
- defaults: ["hidl_defaults"],
-
- srcs: [
- "Component.cpp",
- "ComponentStore.cpp",
- "Configurable.cpp",
- "types.cpp",
- ],
-
- shared_libs: [
- "android.hardware.media.bufferpool@1.0",
- "libcutils",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libutils",
- "vendor.google.media.c2@1.0",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- export_shared_lib_headers: [
- "libstagefright_codec2",
- ],
-
- // Private include directories
- header_libs: [
- "libstagefright_codec2_internal",
- ],
-}
-
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp b/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
deleted file mode 100644
index 2b34fde..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2-Component"
-#include <log/log.h>
-
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/types.h>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using namespace ::android;
-
-// Implementation of ConfigurableC2Intf based on C2ComponentInterface
-struct CompIntf : public ConfigurableC2Intf {
- CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
- ConfigurableC2Intf(intf->getName()),
- mIntf(intf) {
- }
-
- virtual c2_status_t config(
- const std::vector<C2Param*>& params,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures
- ) override {
- return mIntf->config_vb(params, mayBlock, failures);
- }
-
- virtual c2_status_t query(
- const std::vector<C2Param::Index>& indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const override {
- return mIntf->query_vb({}, indices, mayBlock, params);
- }
-
- virtual c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
- ) const override {
- return mIntf->querySupportedParams_nb(params);
- }
-
- virtual c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields,
- c2_blocking_t mayBlock) const override {
- return mIntf->querySupportedValues_vb(fields, mayBlock);
- }
-
-protected:
- std::shared_ptr<C2ComponentInterface> mIntf;
-};
-
-// ComponentInterface
-ComponentInterface::ComponentInterface(
- const std::shared_ptr<C2ComponentInterface>& intf,
- const sp<ComponentStore>& store) :
- Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
- mInterface(intf) {
- mInit = init(store.get());
-}
-
-c2_status_t ComponentInterface::status() const {
- return mInit;
-}
-
-// ComponentListener wrapper
-struct Listener : public C2Component::Listener {
- Listener(const wp<IComponentListener>& listener) : mListener(listener) {
- // TODO: Should we track interface errors? We could reuse onError() or
- // create our own error channel.
- }
-
- virtual void onError_nb(
- std::weak_ptr<C2Component> /* c2component */,
- uint32_t errorCode) override {
- sp<IComponentListener> listener = mListener.promote();
- if (listener) {
- listener->onError(Status::OK, errorCode);
- }
- }
-
- virtual void onTripped_nb(
- std::weak_ptr<C2Component> /* c2component */,
- std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
- ) override {
- sp<IComponentListener> listener = mListener.promote();
- if (listener) {
- hidl_vec<SettingResult> settingResults(c2settingResult.size());
- size_t ix = 0;
- for (const std::shared_ptr<C2SettingResult> &c2result :
- c2settingResult) {
- if (c2result) {
- if (objcpy(&settingResults[ix++], *c2result) != Status::OK) {
- break;
- }
- }
- }
- settingResults.resize(ix);
- listener->onTripped(settingResults);
- }
- }
-
- virtual void onWorkDone_nb(
- std::weak_ptr<C2Component> /* c2component */,
- std::list<std::unique_ptr<C2Work>> c2workItems) override {
- sp<IComponentListener> listener = mListener.promote();
- if (listener) {
- WorkBundle workBundle;
-
- // TODO: Connect with bufferpool API to send Works & Buffers
- if (objcpy(&workBundle, c2workItems) != Status::OK) {
- ALOGE("onWorkDone() received corrupted work items.");
- return;
- }
- listener->onWorkDone(workBundle);
-
- // Finish buffer transfers: nothing else to do
- }
- }
-
-protected:
- wp<IComponentListener> mListener;
-};
-
-// Component
-Component::Component(
- const std::shared_ptr<C2Component>& component,
- const sp<IComponentListener>& listener,
- const sp<ComponentStore>& store) :
- Configurable(new CachedConfigurable(
- std::make_unique<CompIntf>(component->intf()))),
- mComponent(component),
- mInterface(component->intf()),
- mListener(listener) /* , // TODO: Do we need store for anything?
- mStore(store)*/ {
- std::shared_ptr<C2Component::Listener> c2listener =
- std::make_shared<Listener>(listener);
- c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
- // Retrieve supported parameters from store
- // TODO: We could cache this per component/interface type
- mInit = init(store.get());
- mInit = mInit != C2_OK ? res : mInit;
-}
-
-// Methods from ::android::hardware::media::c2::V1_0::IComponent
-Return<Status> Component::queue(const WorkBundle& workBundle) {
- std::list<std::unique_ptr<C2Work>> c2works;
-
- // TODO: Connect with bufferpool API for buffer transfers
- if (objcpy(&c2works, workBundle) != C2_OK) {
- return Status::CORRUPTED;
- }
- return static_cast<Status>(mComponent->queue_nb(&c2works));
-}
-
-Return<void> Component::flush(flush_cb _hidl_cb) {
- std::list<std::unique_ptr<C2Work>> c2flushedWorks;
- c2_status_t c2res = mComponent->flush_sm(
- C2Component::FLUSH_COMPONENT,
- &c2flushedWorks);
- WorkBundle flushedWorkBundle;
-
- Status res = static_cast<Status>(c2res);
- if (c2res == C2_OK) {
- // TODO: Connect with bufferpool API for buffer transfers
- res = objcpy(&flushedWorkBundle, c2flushedWorks);
- }
- _hidl_cb(res, flushedWorkBundle);
- return Void();
-}
-
-Return<Status> Component::drain(bool withEos) {
- return static_cast<Status>(mComponent->drain_nb(withEos ?
- C2Component::DRAIN_COMPONENT_WITH_EOS :
- C2Component::DRAIN_COMPONENT_NO_EOS));
-}
-
-Return<Status> Component::connectToInputSurface(const sp<IInputSurface>& surface) {
- // TODO implement
- (void)surface;
- return Status::OK;
-}
-
-Return<Status> Component::connectToOmxInputSurface(
- const sp<::android::hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer>& producer,
- const sp<::android::hardware::media::omx::V1_0::
- IGraphicBufferSource>& source) {
- // TODO implement
- (void)producer;
- (void)source;
- return Status::OK;
-}
-
-Return<Status> Component::disconnectFromInputSurface() {
- // TODO implement
- return Status::OK;
-}
-
-Return<void> Component::createBlockPool(uint32_t allocatorId, createBlockPool_cb _hidl_cb) {
- // TODO implement
- (void)allocatorId;
- _hidl_cb(Status::OK, 0 /* blockPoolId */, nullptr /* configurable */);
- return Void();
-}
-
-Return<Status> Component::start() {
- return static_cast<Status>(mComponent->start());
-}
-
-Return<Status> Component::stop() {
- return static_cast<Status>(mComponent->stop());
-}
-
-Return<Status> Component::reset() {
- return static_cast<Status>(mComponent->reset());
-}
-
-Return<Status> Component::release() {
- return static_cast<Status>(mComponent->release());
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp b/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
deleted file mode 100644
index 4d51fba..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2-ComponentStore"
-#include <log/log.h>
-
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
-#include <codec2/hidl/1.0/types.h>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using namespace ::android;
-
-struct StoreIntf : public ConfigurableC2Intf {
- StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
- ConfigurableC2Intf(store ? store->getName() : ""),
- mStore(store) {
- }
-
- c2_status_t config(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>> *const failures
- ) override {
- // Assume all params are blocking
- // TODO: Filter for supported params
- if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
- return C2_BLOCKING;
- }
- return mStore->config_sm(params, failures);
- }
-
- c2_status_t query(
- const std::vector<C2Param::Index> &indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>> *const params) const override {
- // Assume all params are blocking
- // TODO: Filter for supported params
- if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
- return C2_BLOCKING;
- }
- return mStore->query_sm({}, indices, params);
- }
-
- c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
- ) const override {
- return mStore->querySupportedParams_nb(params);
- }
-
- c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery> &fields,
- c2_blocking_t mayBlock) const override {
- // Assume all params are blocking
- // TODO: Filter for supported params
- if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
- return C2_BLOCKING;
- }
- return mStore->querySupportedValues_sm(fields);
- }
-
-protected:
- std::shared_ptr<C2ComponentStore> mStore;
-};
-
-
-ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
- Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
- mStore(store) {
- // Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
-
- // Retrieve supported parameters from store
- mInit = init(this);
-}
-
-c2_status_t ComponentStore::validateSupportedParams(
- const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
- c2_status_t res = C2_OK;
-
- for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
- if (!desc) {
- // All descriptors should be valid
- res = res ? res : C2_BAD_VALUE;
- continue;
- }
- C2Param::CoreIndex coreIndex = desc->index().coreIndex();
- auto it = mStructDescriptors.find(coreIndex);
- if (it == mStructDescriptors.end()) {
- std::shared_ptr<C2StructDescriptor> structDesc =
- mParamReflector->describe(coreIndex);
- if (!structDesc) {
- // All supported params must be described
- res = C2_BAD_INDEX;
- }
- mStructDescriptors.insert({ coreIndex, structDesc });
- }
- }
- return res;
-}
-
-// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
-Return<void> ComponentStore::createComponent(
- const hidl_string& name,
- const sp<IComponentListener>& listener,
- // TODO: Return the pool if the component has it.
- const sp<IClientManager>& /* pool */,
- createComponent_cb _hidl_cb) {
- std::shared_ptr<C2Component> c2component;
- c2_status_t res = mStore->createComponent(name, &c2component);
- sp<IComponent> component;
- if (res == C2_OK) {
- component = new Component(c2component, listener, this);
- }
- _hidl_cb((Status)res, component);
- return Void();
-}
-
-Return<void> ComponentStore::createInterface(
- const hidl_string& name,
- createInterface_cb _hidl_cb) {
- std::shared_ptr<C2ComponentInterface> c2interface;
- c2_status_t res = mStore->createInterface(name, &c2interface);
- sp<IComponentInterface> interface;
- if (res == C2_OK) {
- interface = new ComponentInterface(c2interface, this);
- }
- _hidl_cb((Status)res, interface);
- return Void();
-}
-
-Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
- std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
- mStore->listComponents();
- hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
- size_t ix = 0;
- for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
- if (c2trait) {
- objcpy(&traits[ix++], *c2trait);
- }
- }
- traits.resize(ix);
- _hidl_cb(traits);
- return Void();
-}
-
-Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
- // TODO implement
- return sp<IInputSurface> {};
-}
-
-Return<void> ComponentStore::getStructDescriptors(
- const hidl_vec<uint32_t>& indices,
- getStructDescriptors_cb _hidl_cb) {
- hidl_vec<StructDescriptor> descriptors(indices.size());
- size_t dstIx = 0;
- Status res;
- for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
- const auto item = mStructDescriptors.find(
- C2Param::CoreIndex(indices[srcIx]).coreIndex());
- if (item == mStructDescriptors.end()) {
- res = Status::NOT_FOUND;
- } else if (item->second) {
- objcpy(&descriptors[dstIx++], *item->second);
- } else {
- res = Status::NO_MEMORY;
- }
- }
- descriptors.resize(dstIx);
- _hidl_cb(res, descriptors);
- return Void();
-}
-
-Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
- // TODO implement
- return sp<IClientManager> {};
-}
-
-Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
- // TODO implement
- (void)src;
- (void)dst;
- return Status::OMITTED;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp b/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp
deleted file mode 100644
index 3f041a9..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/Configurable.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2-Configurable"
-#include <log/log.h>
-
-#include <codec2/hidl/1.0/Configurable.h>
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/types.h>
-#include <C2ParamInternal.h>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using namespace ::android;
-
-CachedConfigurable::CachedConfigurable(
- std::unique_ptr<ConfigurableC2Intf>&& intf) :
- mIntf(std::move(intf)) {
-}
-
-c2_status_t CachedConfigurable::init(ComponentStore* store) {
- // Retrieve supported parameters from store
- c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
- c2_status_t validate = store->validateSupportedParams(mSupportedParams);
- return init == C2_OK ? C2_OK : validate;
-}
-
-// Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
-Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
- _hidl_cb(mIntf->getName());
- return Void();
-}
-
-Return<void> CachedConfigurable::query(
- const hidl_vec<uint32_t>& indices,
- bool mayBlock,
- query_cb _hidl_cb) {
- typedef C2Param::Index Index;
- std::vector<Index> c2heapParamIndices(
- (Index*)indices.data(),
- (Index*)indices.data() + indices.size());
- std::vector<std::unique_ptr<C2Param>> c2heapParams;
- c2_status_t c2res = mIntf->query(
- c2heapParamIndices,
- mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
- &c2heapParams);
-
- hidl_vec<uint8_t> params;
- createParamsBlob(¶ms, c2heapParams);
- _hidl_cb(static_cast<Status>(c2res), params);
-
- return Void();
-}
-
-Return<void> CachedConfigurable::config(
- const hidl_vec<uint8_t>& inParams,
- bool mayBlock,
- config_cb _hidl_cb) {
- std::vector<C2Param*> c2params;
- if (parseParamsBlob(&c2params, inParams) != C2_OK) {
- _hidl_cb(Status::CORRUPTED,
- hidl_vec<SettingResult>(),
- hidl_vec<uint8_t>());
- return Void();
- }
- // TODO: check if blob was invalid
- std::vector<std::unique_ptr<C2SettingResult>> c2failures;
- c2_status_t c2res = mIntf->config(
- c2params,
- mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
- &c2failures);
- hidl_vec<SettingResult> failures(c2failures.size());
- {
- size_t ix = 0;
- for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
- if (c2result) {
- objcpy(&failures[ix++], *c2result);
- }
- }
- failures.resize(ix);
- }
- hidl_vec<uint8_t> outParams;
- createParamsBlob(&outParams, c2params);
- _hidl_cb((Status)c2res, failures, outParams);
- return Void();
-}
-
-Return<void> CachedConfigurable::querySupportedParams(
- uint32_t start,
- uint32_t count,
- querySupportedParams_cb _hidl_cb) {
- C2LinearRange request = C2LinearCapacity(mSupportedParams.size()).range(
- start, count);
- hidl_vec<ParamDescriptor> params(request.size());
- Status res = Status::OK;
- size_t dstIx = 0;
- for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
- if (mSupportedParams[srcIx]) {
- objcpy(¶ms[dstIx++], *mSupportedParams[srcIx]);
- } else {
- res = Status::CORRUPTED;
- }
- }
- params.resize(dstIx);
- _hidl_cb(res, params);
- return Void();
-}
-
-Return<void> CachedConfigurable::querySupportedValues(
- const hidl_vec<FieldSupportedValuesQuery>& inFields,
- bool mayBlock,
- querySupportedValues_cb _hidl_cb) {
- std::vector<C2FieldSupportedValuesQuery> c2fields;
- {
- // C2FieldSupportedValuesQuery objects are restricted in that some
- // members are const.
- // C2ParamField - required for its constructor - has no constructors
- // from fields. Use C2ParamInspector.
- for (const FieldSupportedValuesQuery &query : inFields) {
- c2fields.emplace_back(_C2ParamInspector::CreateParamField(
- query.field.index,
- query.field.fieldId.offset,
- query.field.fieldId.size),
- query.type == FieldSupportedValuesQuery::Type::POSSIBLE ?
- C2FieldSupportedValuesQuery::POSSIBLE :
- C2FieldSupportedValuesQuery::CURRENT);
- }
- }
- c2_status_t c2res = mIntf->querySupportedValues(
- c2fields,
- mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
- hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
- {
- size_t ix = 0;
- for (const C2FieldSupportedValuesQuery &result : c2fields) {
- objcpy(&outFields[ix++], result);
- }
- }
- _hidl_cb((Status)c2res, outFields);
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h
deleted file mode 100644
index 0308fe0..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Component.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
-#define VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
-
-#include <codec2/hidl/1.0/Configurable.h>
-
-#include <vendor/google/media/c2/1.0/IComponentListener.h>
-#include <vendor/google/media/c2/1.0/IComponentStore.h>
-#include <vendor/google/media/c2/1.0/IComponent.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <C2Component.h>
-#include <C2.h>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct ComponentStore;
-
-struct ComponentInterface : public Configurable<IComponentInterface> {
- ComponentInterface(
- const std::shared_ptr<C2ComponentInterface>& interface,
- const sp<ComponentStore>& store);
- c2_status_t status() const;
-
-protected:
- c2_status_t mInit;
- std::shared_ptr<C2ComponentInterface> mInterface;
- // sp<ComponentStore> mStore; // TODO needed?
-};
-
-struct Component : public Configurable<IComponent> {
- Component(
- const std::shared_ptr<C2Component>&,
- const sp<IComponentListener>& listener,
- const sp<ComponentStore>& store);
-
- // Methods from gIComponent follow.
- virtual Return<Status> queue(const WorkBundle& workBundle) override;
- virtual Return<void> flush(flush_cb _hidl_cb) override;
- virtual Return<Status> drain(bool withEos) override;
- virtual Return<Status> connectToInputSurface(
- const sp<IInputSurface>& surface) override;
- virtual Return<Status> connectToOmxInputSurface(
- const sp<::android::hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer>& producer,
- const sp<::android::hardware::media::omx::V1_0::
- IGraphicBufferSource>& source) override;
- virtual Return<Status> disconnectFromInputSurface() override;
- virtual Return<void> createBlockPool(
- uint32_t allocatorId,
- createBlockPool_cb _hidl_cb) override;
- virtual Return<Status> start() override;
- virtual Return<Status> stop() override;
- virtual Return<Status> reset() override;
- virtual Return<Status> release() override;
-
-protected:
- c2_status_t mInit;
- std::shared_ptr<C2Component> mComponent;
- std::shared_ptr<C2ComponentInterface> mInterface;
- sp<IComponentListener> mListener;
- // sp<ComponentStore> mStore; // TODO needed?
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-#endif // VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENT_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h
deleted file mode 100644
index c3f92a0..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ComponentStore.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
-#define VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
-
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/Configurable.h>
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <vendor/google/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <vector>
-#include <map>
-#include <memory>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::bufferpool::V1_0::IClientManager;
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct ComponentStore : public Configurable<IComponentStore> {
- ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
- virtual ~ComponentStore() = default;
-
- c2_status_t status() const {
- return mInit;
- }
-
- c2_status_t validateSupportedParams(
- const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
-
- // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
- Return<void> createComponent(
- const hidl_string& name,
- const sp<IComponentListener>& listener,
- const sp<IClientManager>& pool,
- createComponent_cb _hidl_cb) override;
- Return<void> createInterface(
- const hidl_string& name,
- createInterface_cb _hidl_cb) override;
- Return<void> listComponents(listComponents_cb _hidl_cb) override;
- Return<sp<IInputSurface>> createInputSurface() override;
- Return<void> getStructDescriptors(
- const hidl_vec<uint32_t>& indices,
- getStructDescriptors_cb _hidl_cb) override;
- Return<sp<IClientManager>> getPoolClientManager() override;
- Return<Status> copyBuffer(
- const Buffer& src,
- const Buffer& dst) override;
-
-protected:
- c2_status_t mInit;
- std::shared_ptr<C2ComponentStore> mStore;
- std::shared_ptr<C2ParamReflector> mParamReflector;
- std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>>
- mStructDescriptors;
-
- sp<IClientManager> mPoolManager;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-#endif // VENDOR_GOOGLE_MEDIA_C2_V1_0_COMPONENTSTORE_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h
deleted file mode 100644
index 697d483..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/Configurable.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
-#define VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
-
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
-
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <vendor/google/media/c2/1.0/IConfigurable.h>
-#include <hidl/Status.h>
-
-#include <memory>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct ComponentStore;
-
-/**
- * Implementation of the IConfigurable interface that supports caching of
- * supported parameters from a supplied ComponentStore.
- *
- * This is mainly the same for all of the configurable C2 interfaces though
- * there are slight differences in the blocking behavior. This is handled in the
- * ConfigurableC2Intf implementations.
- */
-struct CachedConfigurable : public IConfigurable {
- CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
-
- c2_status_t init(ComponentStore* store);
-
- // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
-
- virtual Return<void> getName(getName_cb _hidl_cb) override;
-
- virtual Return<void> query(
- const hidl_vec<uint32_t>& indices,
- bool mayBlock,
- query_cb _hidl_cb) override;
-
- virtual Return<void> config(
- const hidl_vec<uint8_t>& inParams,
- bool mayBlock,
- config_cb _hidl_cb) override;
-
- virtual Return<void> querySupportedParams(
- uint32_t start,
- uint32_t count,
- querySupportedParams_cb _hidl_cb) override;
-
- virtual Return<void> querySupportedValues(
- const hidl_vec<FieldSupportedValuesQuery>& inFields,
- bool mayBlock,
- querySupportedValues_cb _hidl_cb) override;
-
-protected:
- // Common Codec2.0 interface wrapper
- std::unique_ptr<ConfigurableC2Intf> mIntf;
-
- // Cached supported params
- std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
-};
-
-/**
- * Template that implements the `IConfigurable` interface for an inherited
- * interface. Classes that implement a child interface `I` of `IConfigurable`
- * can derive from `Configurable<I>`.
- */
-template <typename I>
-struct Configurable : public I {
- Configurable(const sp<CachedConfigurable>& intf): mIntf(intf) {
- }
-
- c2_status_t init(ComponentStore* store) {
- return mIntf->init(store);
- }
-
- // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
-
- using getName_cb = typename I::getName_cb;
- virtual Return<void> getName(getName_cb _hidl_cb) override {
- return mIntf->getName(_hidl_cb);
- }
-
- using query_cb = typename I::query_cb;
- virtual Return<void> query(
- const hidl_vec<uint32_t>& indices,
- bool mayBlock,
- query_cb _hidl_cb) override {
- return mIntf->query(indices, mayBlock, _hidl_cb);
- }
-
- using config_cb = typename I::config_cb;
- virtual Return<void> config(
- const hidl_vec<uint8_t>& inParams,
- bool mayBlock,
- config_cb _hidl_cb) override {
- return mIntf->config(inParams, mayBlock, _hidl_cb);
- }
-
- using querySupportedParams_cb = typename I::querySupportedParams_cb;
- virtual Return<void> querySupportedParams(
- uint32_t start,
- uint32_t count,
- querySupportedParams_cb _hidl_cb) override {
- return mIntf->querySupportedParams(start, count, _hidl_cb);
- }
-
- using querySupportedValues_cb = typename I::querySupportedValues_cb;
- virtual Return<void> querySupportedValues(
- const hidl_vec<FieldSupportedValuesQuery>& inFields,
- bool mayBlock,
- querySupportedValues_cb _hidl_cb) override {
- return mIntf->querySupportedValues(inFields, mayBlock, _hidl_cb);
- }
-
-protected:
- sp<CachedConfigurable> mIntf;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-#endif // VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLE_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
deleted file mode 100644
index da90996..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
-#define VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
-
-#include <C2Work.h>
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <hidl/HidlSupport.h>
-#include <utils/StrongPointer.h>
-#include <vector>
-#include <memory>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-/**
- * Common Codec 2.0 interface wrapper.
- */
-struct ConfigurableC2Intf {
- C2String getName() const { return mName; }
- /** C2ComponentInterface::query_vb sans stack params */
- virtual c2_status_t query(
- const std::vector<C2Param::Index> &indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
- /** C2ComponentInterface::config_vb */
- virtual c2_status_t config(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
- /** C2ComponentInterface::querySupportedParams_nb */
- virtual c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
- /** C2ComponentInterface::querySupportedParams_nb */
- virtual c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
-
- virtual ~ConfigurableC2Intf() = default;
-
- ConfigurableC2Intf(const C2String& name) : mName(name) {}
-
-protected:
- C2String mName; /* cache component name */
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-#endif // VENDOR_GOOGLE_MEDIA_C2_V1_0_CONFIGURABLEC2INTF_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
deleted file mode 100644
index 1eace56..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
-#define VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
-
-#include <vendor/google/media/c2/1.0/types.h>
-#include <vendor/google/media/c2/1.0/IComponentStore.h>
-
-#include <C2Param.h>
-#include <C2Component.h>
-#include <C2Work.h>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_bitfield;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::sp;
-
-// Types of metadata for Blocks.
-struct C2Hidl_Range {
- uint32_t offset;
- uint32_t length; // Do not use "size" because the name collides with C2Info::size().
-};
-typedef C2GlobalParam<C2Info, C2Hidl_Range, 0> C2Hidl_RangeInfo;
-
-struct C2Hidl_Rect {
- uint32_t left;
- uint32_t top;
- uint32_t width;
- uint32_t height;
-};
-typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
-
-// C2SettingResult -> SettingResult
-Status objcpy(
- SettingResult* d,
- const C2SettingResult& s);
-
-// SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(
- std::unique_ptr<C2SettingResult>* d,
- const SettingResult& s);
-
-// C2ParamDescriptor -> ParamDescriptor
-Status objcpy(
- ParamDescriptor* d,
- const C2ParamDescriptor& s);
-
-// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
-c2_status_t objcpy(
- std::shared_ptr<C2ParamDescriptor>* d,
- const ParamDescriptor& s);
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
- FieldSupportedValuesQuery* d,
- const C2FieldSupportedValuesQuery& s);
-
-// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
- C2FieldSupportedValuesQuery* d,
- const FieldSupportedValuesQuery& s);
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
- FieldSupportedValuesQueryResult* d,
- const C2FieldSupportedValuesQuery& s);
-
-// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
- C2FieldSupportedValuesQuery* d,
- const FieldSupportedValuesQuery& sq,
- const FieldSupportedValuesQueryResult& sr);
-
-// C2Component::Traits -> ComponentTraits
-Status objcpy(
- IComponentStore::ComponentTraits* d,
- const C2Component::Traits& s);
-
-// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-// Note: The output d is only valid as long as aliasesBuffer remains alive.
-c2_status_t objcpy(
- C2Component::Traits* d,
- std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
- const IComponentStore::ComponentTraits& s);
-
-// C2StructDescriptor -> StructDescriptor
-Status objcpy(
- StructDescriptor* d,
- const C2StructDescriptor& s);
-
-// StructDescriptor -> C2StructDescriptor
-// TODO: This cannot be implemented yet because C2StructDescriptor does not
-// allow dynamic construction/modification.
-c2_status_t objcpy(
- C2StructDescriptor* d,
- const StructDescriptor& s);
-
-// std::list<std::unique_ptr<C2Work>> -> WorkBundle
-// TODO: Connect with Bufferpool
-Status objcpy(
- WorkBundle* d,
- const std::list<std::unique_ptr<C2Work>>& s);
-
-// WorkBundle -> std::list<std::unique_ptr<C2Work>>
-// TODO: Connect with Bufferpool
-c2_status_t objcpy(
- std::list<std::unique_ptr<C2Work>>* d,
- const WorkBundle& s);
-
-/**
- * Parses a params blob and returns C2Param pointers to its params.
- * \param[out] params target vector of C2Param pointers
- * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed
- * \retval C2_BAD_VALUE otherwise
- */
-c2_status_t parseParamsBlob(
- std::vector<C2Param*> *params,
- const hidl_vec<uint8_t> &blob);
-
-/**
- * Concatenates a list of C2Params into a params blob.
- * \param[out] blob target blob
- * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- * not const)
- */
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<C2Param*> ¶ms);
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::unique_ptr<C2Param>> ¶ms);
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::shared_ptr<const C2Info>> ¶ms);
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::unique_ptr<C2Tuning>> ¶ms);
-
-/**
- * Parses a params blob and create a vector of C2Params whose members are copies
- * of the params in the blob.
- * \param[out] params the resulting vector
- * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
- */
-c2_status_t copyParamsFromBlob(
- std::vector<std::unique_ptr<C2Param>>* params,
- Params blob);
-
-/**
- * Parses a params blob and applies updates to params
- * \param[in,out] params params to be updated
- * \param[in] blob parameter blob containing updates
- * \retval C2_OK if the full blob was parsed and params was updated
- * \retval C2_BAD_VALUE otherwise
- */
-c2_status_t updateParamsFromBlob(
- const std::vector<C2Param*>& params,
- const Params& blob);
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace google
-} // namespace vendor
-
-#endif // VENDOR_GOOGLE_MEDIA_C2_V1_0_TYPES_H
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/types.cpp b/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
deleted file mode 100644
index f14c21a..0000000
--- a/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Codec2-types"
-#include <log/log.h>
-
-#include <codec2/hidl/1.0/types.h>
-
-#include <C2AllocatorIon.h>
-#include <C2AllocatorGralloc.h>
-#include <C2PlatformSupport.h>
-#include <C2BlockInternal.h>
-#include <C2ParamInternal.h>
-#include <C2Param.h>
-#include <C2Buffer.h>
-#include <C2Work.h>
-#include <C2Component.h>
-#include <util/C2ParamUtils.h>
-
-#include <unordered_map>
-#include <algorithm>
-
-namespace vendor {
-namespace google {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using namespace ::android;
-
-namespace /* unnamed */ {
-
-template <typename Common, typename DstVector, typename SrcVector>
-void copyVector(DstVector* d, const SrcVector& s) {
- static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
- "DstVector's component size does not match Common");
- static_assert(sizeof(Common) == sizeof(decltype(s[0])),
- "SrcVector's component size does not match Common");
- d->resize(s.size());
- std::copy(
- reinterpret_cast<const Common*>(&s[0]),
- reinterpret_cast<const Common*>(&s[0] + s.size()),
- reinterpret_cast<Common*>(&(*d)[0]));
-}
-
-// C2ParamField -> ParamField
-void objcpy(ParamField *d, const C2ParamField &s) {
- d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
- d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
- d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
-}
-
-struct C2ParamFieldBuilder : public C2ParamField {
- C2ParamFieldBuilder() : C2ParamField(
- static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
- }
- // ParamField -> C2ParamField
- C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
- static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
- static_cast<uint32_t>(s.fieldId.offset),
- static_cast<uint32_t>(s.fieldId.size)) {
- }
-};
-
-// C2WorkOrdinalStruct -> WorkOrdinal
-void objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
- d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
- d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
- d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
-}
-
-// WorkOrdinal -> C2WorkOrdinalStruct
-void objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
- d->frameIndex = c2_cntr64_t(s.frameIndex);
- d->timestamp = c2_cntr64_t(s.timestampUs);
- d->customOrdinal = c2_cntr64_t(s.customOrdinal);
-}
-
-// C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
-void objcpy(
- FieldSupportedValues::Range* d,
- const decltype(C2FieldSupportedValues::range)& s) {
- d->min = static_cast<PrimitiveValue>(s.min.u64);
- d->max = static_cast<PrimitiveValue>(s.max.u64);
- d->step = static_cast<PrimitiveValue>(s.step.u64);
- d->num = static_cast<PrimitiveValue>(s.num.u64);
- d->denom = static_cast<PrimitiveValue>(s.denom.u64);
-}
-
-// C2FieldSupportedValues -> FieldSupportedValues
-Status objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
- d->typeOther = static_cast<int32_t>(s.type);
- switch (s.type) {
- case C2FieldSupportedValues::EMPTY:
- d->type = FieldSupportedValues::Type::EMPTY;
- d->values.resize(0);
- return Status::OK;
- case C2FieldSupportedValues::RANGE:
- d->type = FieldSupportedValues::Type::RANGE;
- objcpy(&d->range, s.range);
- d->values.resize(0);
- return Status::OK;
- default:
- switch (s.type) {
- case C2FieldSupportedValues::VALUES:
- d->type = FieldSupportedValues::Type::VALUES;
- break;
- case C2FieldSupportedValues::FLAGS:
- d->type = FieldSupportedValues::Type::FLAGS;
- break;
- default:
- d->type = FieldSupportedValues::Type::OTHER;
- // Copy all fields in this case
- objcpy(&d->range, s.range);
- }
- d->values.resize(s.values.size());
- copyVector<uint64_t>(&d->values, s.values);
- return Status::OK;
- }
-}
-
-// FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
-void objcpy(
- decltype(C2FieldSupportedValues::range)* d,
- const FieldSupportedValues::Range& s) {
- d->min.u64 = static_cast<uint64_t>(s.min);
- d->max.u64 = static_cast<uint64_t>(s.max);
- d->step.u64 = static_cast<uint64_t>(s.step);
- d->num.u64 = static_cast<uint64_t>(s.num);
- d->denom.u64 = static_cast<uint64_t>(s.denom);
-}
-
-// FieldSupportedValues -> C2FieldSupportedValues
-c2_status_t objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
- switch (s.type) {
- case FieldSupportedValues::Type::EMPTY:
- d->type = C2FieldSupportedValues::EMPTY;
- return C2_OK;
- case FieldSupportedValues::Type::RANGE:
- d->type = C2FieldSupportedValues::RANGE;
- objcpy(&d->range, s.range);
- d->values.resize(0);
- return C2_OK;
- default:
- switch (s.type) {
- case FieldSupportedValues::Type::VALUES:
- d->type = C2FieldSupportedValues::VALUES;
- break;
- case FieldSupportedValues::Type::FLAGS:
- d->type = C2FieldSupportedValues::FLAGS;
- break;
- default:
- d->type = static_cast<C2FieldSupportedValues::type_t>(s.typeOther);
- // Copy all fields in this case
- objcpy(&d->range, s.range);
- }
- copyVector<uint64_t>(&d->values, s.values);
- return C2_OK;
- }
-}
-
-} // unnamed namespace
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
- FieldSupportedValuesQuery* d,
- const C2FieldSupportedValuesQuery& s) {
- objcpy(&d->field, s.field());
- switch (s.type()) {
- case C2FieldSupportedValuesQuery::POSSIBLE:
- d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
- break;
- case C2FieldSupportedValuesQuery::CURRENT:
- d->type = FieldSupportedValuesQuery::Type::CURRENT;
- break;
- default:
- ALOGE("Unknown type of C2FieldSupportedValuesQuery: %u",
- static_cast<unsigned>(s.type()));
- return Status::BAD_VALUE;
- }
- return Status::OK;
-}
-
-// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
- C2FieldSupportedValuesQuery* d,
- const FieldSupportedValuesQuery& s) {
- C2FieldSupportedValuesQuery::type_t dType;
- switch (s.type) {
- case FieldSupportedValuesQuery::Type::POSSIBLE:
- dType = C2FieldSupportedValuesQuery::POSSIBLE;
- break;
- case FieldSupportedValuesQuery::Type::CURRENT:
- dType = C2FieldSupportedValuesQuery::CURRENT;
- break;
- default:
- ALOGE("Unknown type of FieldSupportedValuesQuery: %u",
- static_cast<unsigned>(s.type));
- return C2_BAD_VALUE;
- }
- *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
- return C2_OK;
-}
-
-// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
- FieldSupportedValuesQueryResult* d,
- const C2FieldSupportedValuesQuery& s) {
- d->status = static_cast<Status>(s.status);
- return objcpy(&d->values, s.values);
-}
-
-// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
-// C2FieldSupportedValuesQuery
-c2_status_t objcpy(
- C2FieldSupportedValuesQuery* d,
- const FieldSupportedValuesQuery& sq,
- const FieldSupportedValuesQueryResult& sr) {
- c2_status_t status = objcpy(d, sq);
- if (status != C2_OK) {
- return status;
- }
- d->status = static_cast<c2_status_t>(sr.status);
- return objcpy(&d->values, sr.values);
-}
-
-// C2Component::Traits -> IComponentStore::ComponentTraits
-Status objcpy(
- IComponentStore::ComponentTraits *d,
- const C2Component::Traits &s) {
- d->name = s.name;
-
- // TODO: Currently, we do not have any domain values defined in Codec2.0.
- d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
- d->domainOther = static_cast<uint32_t>(s.domain);
-
- // TODO: Currently, we do not have any kind values defined in Codec2.0.
- d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
- d->kindOther = static_cast<uint32_t>(s.kind);
-
- d->rank = static_cast<uint32_t>(s.rank);
-
- d->mediaType = s.mediaType;
-
- d->aliases.resize(s.aliases.size());
- for (size_t ix = s.aliases.size(); ix > 0; ) {
- --ix;
- d->aliases[ix] = s.aliases[ix];
- }
- return Status::OK;
-}
-
-// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-c2_status_t objcpy(
- C2Component::Traits* d,
- std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
- const IComponentStore::ComponentTraits& s) {
- d->name = s.name.c_str();
- d->domain = static_cast<C2Component::domain_t>(s.domainOther);
- d->kind = static_cast<C2Component::kind_t>(s.kindOther);
- d->rank = static_cast<C2Component::rank_t>(s.rank);
- d->mediaType = s.mediaType.c_str();
-
- // aliasesBuffer must not be resized after this.
- *aliasesBuffer = std::make_unique<std::vector<std::string>>(
- s.aliases.size());
- (*aliasesBuffer)->resize(s.aliases.size());
- std::vector<C2StringLiteral> dAliases(s.aliases.size());
- for (size_t i = 0; i < s.aliases.size(); ++i) {
- (**aliasesBuffer)[i] = s.aliases[i].c_str();
- d->aliases[i] = (**aliasesBuffer)[i].c_str();
- }
- return C2_OK;
-}
-
-namespace /* unnamed */ {
-
-// C2ParamFieldValues -> ParamFieldValues
-Status objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
- objcpy(&d->paramOrField, s.paramOrField);
- if (s.values) {
- d->values.resize(1);
- return objcpy(&d->values[0], *s.values);
- }
- d->values.resize(0);
- return Status::OK;
-}
-
-// ParamFieldValues -> C2ParamFieldValues
-c2_status_t objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
- d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
- if (s.values.size() == 1) {
- d->values = std::make_unique<C2FieldSupportedValues>();
- return objcpy(d->values.get(), s.values[0]);
- } else if (s.values.size() == 0) {
- d->values.reset();
- return C2_OK;
- }
- ALOGE("Multiple FieldSupportedValues objects. "
- "(Only one is allowed.)");
- return C2_BAD_VALUE;
-}
-
-} // unnamed namespace
-
-// C2SettingResult -> SettingResult
-Status objcpy(SettingResult *d, const C2SettingResult &s) {
- d->failureOther = static_cast<uint32_t>(s.failure);
- switch (s.failure) {
- case C2SettingResult::READ_ONLY:
- d->failure = SettingResult::Failure::READ_ONLY;
- break;
- case C2SettingResult::MISMATCH:
- d->failure = SettingResult::Failure::MISMATCH;
- break;
- case C2SettingResult::BAD_VALUE:
- d->failure = SettingResult::Failure::BAD_VALUE;
- break;
- case C2SettingResult::BAD_TYPE:
- d->failure = SettingResult::Failure::BAD_TYPE;
- break;
- case C2SettingResult::BAD_PORT:
- d->failure = SettingResult::Failure::BAD_PORT;
- break;
- case C2SettingResult::BAD_INDEX:
- d->failure = SettingResult::Failure::BAD_INDEX;
- break;
- case C2SettingResult::CONFLICT:
- d->failure = SettingResult::Failure::CONFLICT;
- break;
- case C2SettingResult::UNSUPPORTED:
- d->failure = SettingResult::Failure::UNSUPPORTED;
- break;
- case C2SettingResult::INFO_CONFLICT:
- d->failure = SettingResult::Failure::INFO_CONFLICT;
- break;
- default:
- d->failure = SettingResult::Failure::OTHER;
- }
- Status status = objcpy(&d->field, s.field);
- if (status != Status::OK) {
- return status;
- }
- d->conflicts.resize(s.conflicts.size());
- size_t i = 0;
- for (const C2ParamFieldValues& sConflict : s.conflicts) {
- ParamFieldValues &dConflict = d->conflicts[i++];
- status = objcpy(&dConflict, sConflict);
- if (status != Status::OK) {
- return status;
- }
- }
- return Status::OK;
-}
-
-// SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
- *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
- .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
- if (!*d) {
- return C2_NO_MEMORY;
- }
-
- // failure
- switch (s.failure) {
- case SettingResult::Failure::READ_ONLY:
- (*d)->failure = C2SettingResult::READ_ONLY;
- break;
- case SettingResult::Failure::MISMATCH:
- (*d)->failure = C2SettingResult::MISMATCH;
- break;
- case SettingResult::Failure::BAD_VALUE:
- (*d)->failure = C2SettingResult::BAD_VALUE;
- break;
- case SettingResult::Failure::BAD_TYPE:
- (*d)->failure = C2SettingResult::BAD_TYPE;
- break;
- case SettingResult::Failure::BAD_PORT:
- (*d)->failure = C2SettingResult::BAD_PORT;
- break;
- case SettingResult::Failure::BAD_INDEX:
- (*d)->failure = C2SettingResult::BAD_INDEX;
- break;
- case SettingResult::Failure::CONFLICT:
- (*d)->failure = C2SettingResult::CONFLICT;
- break;
- case SettingResult::Failure::UNSUPPORTED:
- (*d)->failure = C2SettingResult::UNSUPPORTED;
- break;
- case SettingResult::Failure::INFO_CONFLICT:
- (*d)->failure = C2SettingResult::INFO_CONFLICT;
- break;
- default:
- (*d)->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
- }
-
- // field
- c2_status_t status = objcpy(&(*d)->field, s.field);
- if (status != C2_OK) {
- return status;
- }
-
- // conflicts
- (*d)->conflicts.clear();
- (*d)->conflicts.reserve(s.conflicts.size());
- for (const ParamFieldValues& sConflict : s.conflicts) {
- (*d)->conflicts.emplace_back(
- C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
- status = objcpy(&(*d)->conflicts.back(), sConflict);
- if (status != C2_OK) {
- return status;
- }
- }
- return C2_OK;
-}
-
-// C2ParamDescriptor -> ParamDescriptor
-Status objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
- d->index = static_cast<ParamIndex>(s.index());
- d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
- _C2ParamInspector::GetAttrib(s));
- d->name = s.name();
- copyVector<uint32_t>(&d->dependencies, s.dependencies());
- return Status::OK;
-}
-
-// ParamDescriptor -> C2ParamDescriptor
-c2_status_t objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
- std::vector<C2Param::Index> dDependencies;
- dDependencies.reserve(s.dependencies.size());
- for (const ParamIndex& sDependency : s.dependencies) {
- dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
- }
- *d = std::make_shared<C2ParamDescriptor>(
- C2Param::Index(static_cast<uint32_t>(s.index)),
- static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
- C2String(s.name.c_str()),
- std::move(dDependencies));
- return C2_OK;
-}
-
-// C2StructDescriptor -> StructDescriptor
-Status objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
- d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
- d->fields.resize(s.numFields());
- size_t i = 0;
- for (const auto& sField : s) {
- FieldDescriptor& dField = d->fields[i++];
- dField.fieldId.offset = static_cast<uint32_t>(
- _C2ParamInspector::GetOffset(sField));
- dField.fieldId.size = static_cast<uint32_t>(
- _C2ParamInspector::GetSize(sField));
- dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
- sField.type());
- dField.length = static_cast<uint32_t>(sField.extent());
- dField.name = static_cast<hidl_string>(sField.name());
- const auto& sNamedValues = sField.namedValues();
- dField.namedValues.resize(sNamedValues.size());
- size_t j = 0;
- for (const auto& sNamedValue : sNamedValues) {
- FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
- dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
- dNamedValue.value = static_cast<PrimitiveValue>(
- sNamedValue.second.u64);
- }
- }
- return Status::OK;
-}
-
-// StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(C2StructDescriptor *d, const StructDescriptor &s) {
- // TODO: Implement this when C2StructDescriptor can be dynamically
- // constructed.
- (void)d;
- (void)s;
- ALOGE("Conversion StructDescriptor -> C2StructDescriptor "
- "not implemented.");
- return C2_OMITTED;
-}
-
-// Finds or adds a hidl BaseBlock object from a given C2Handle* to a list and an
-// associated map.
-// Note: Native handles are not duplicated. The original handles must not be
-// closed before the transaction is complete.
-namespace /* unnamed */ {
-
-Status addBaseBlock(uint32_t* index, const C2Handle* handle,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- if (handle == nullptr) {
- return Status::BAD_VALUE;
- }
- auto it = baseBlockIndices->find(handle);
- if (it != baseBlockIndices->end()) {
- *index = it->second;
- } else {
- *index = baseBlocks->size();
- BaseBlock dBaseBlock;
- // TODO: Use BufferPool.
- dBaseBlock.type = BaseBlock::Type::NATIVE;
- // This does not clone the handle.
- dBaseBlock.nativeBlock =
- reinterpret_cast<const native_handle_t*>(handle);
- baseBlocks->push_back(dBaseBlock);
- baseBlockIndices->emplace(handle, *index);
- }
- return Status::OK;
-}
-
-// C2Fence -> hidl_handle
-// Note: File descriptors are not duplicated. The original file descriptor must
-// not be closed before the transaction is complete.
-Status objcpy(hidl_handle* d, const C2Fence& s) {
- (void)s; // TODO: implement s.fd()
- int fenceFd = -1;
- d->setTo(nullptr);
- if (fenceFd >= 0) {
- native_handle_t *handle = native_handle_create(1, 0);
- if (!handle) {
- return Status::NO_MEMORY;
- }
- handle->data[0] = fenceFd;
- d->setTo(handle, true /* owns */);
- }
- return Status::OK;
-}
-
-// C2ConstLinearBlock -> Block
-// Note: Native handles are not duplicated. The original handles must not be
-// closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstLinearBlock& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- // Find the BaseBlock index.
- // TODO: Use BufferPool.
- Status status = addBaseBlock(
- &d->index, s.handle(), baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
-
- // Create the metadata.
- C2Hidl_RangeInfo dRangeInfo;
- dRangeInfo.offset = static_cast<uint32_t>(s.offset());
- dRangeInfo.length = static_cast<uint32_t>(s.size());
- status = createParamsBlob(&d->meta,
- std::vector<C2Param*>{ &dRangeInfo });
- if (status != Status::OK) {
- return Status::BAD_VALUE;
- }
-
- // Copy the fence
- return objcpy(&d->fence, s.fence());
-}
-
-// C2ConstGraphicBlock -> Block
-// Note: Native handles are not duplicated. The original handles must not be
-// closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstGraphicBlock& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- // Find the BaseBlock index.
- // TODO: Use BufferPool.
- Status status = addBaseBlock(
- &d->index, s.handle(), baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
-
- // Create the metadata.
- C2Hidl_RectInfo dRectInfo;
- C2Rect sRect = s.crop();
- dRectInfo.left = static_cast<uint32_t>(sRect.left);
- dRectInfo.top = static_cast<uint32_t>(sRect.top);
- dRectInfo.width = static_cast<uint32_t>(sRect.width);
- dRectInfo.height = static_cast<uint32_t>(sRect.height);
- status = createParamsBlob(&d->meta,
- std::vector<C2Param*>{ &dRectInfo });
- if (status != Status::OK) {
- return Status::BAD_VALUE;
- }
-
- // Copy the fence
- return objcpy(&d->fence, s.fence());
-}
-
-// C2BufferData -> Buffer
-// This function only fills in d->blocks.
-Status objcpy(Buffer* d, const C2BufferData& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- Status status;
- d->blocks.resize(
- s.linearBlocks().size() +
- s.graphicBlocks().size());
- size_t i = 0;
- for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
- Block& dBlock = d->blocks[i++];
- status = objcpy(
- &dBlock, linearBlock, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- }
- for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
- Block& dBlock = d->blocks[i++];
- status = objcpy(
- &dBlock, graphicBlock, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- }
- return Status::OK;
-}
-
-// C2Buffer -> Buffer
-Status objcpy(Buffer* d, const C2Buffer& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- Status status = createParamsBlob(&d->info, s.info());
- if (status != Status::OK) {
- return status;
- }
- return objcpy(d, s.data(), baseBlocks, baseBlockIndices);
-}
-
-// C2InfoBuffer -> InfoBuffer
-Status objcpy(InfoBuffer* d, const C2InfoBuffer& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- // TODO: C2InfoBuffer is not implemented.
- (void)d;
- (void)s;
- (void)baseBlocks;
- (void)baseBlockIndices;
- return Status::OK;
- /*
- // Stub implementation that may work in the future.
- d->index = static_cast<uint32_t>(s.index());
- d->buffer.info.resize(0);
- return objcpy(&d->buffer, s.data(), baseBlocks, baseBlockIndices);
- */
-}
-
-// C2FrameData -> FrameData
-Status objcpy(FrameData* d, const C2FrameData& s,
- std::vector<BaseBlock>* baseBlocks,
- std::map<const C2Handle*, uint32_t>* baseBlockIndices) {
- d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
- objcpy(&d->ordinal, s.ordinal);
-
- Status status;
- d->buffers.resize(s.buffers.size());
- size_t i = 0;
- for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
- Buffer& dBuffer = d->buffers[i++];
- if (!sBuffer) {
- ALOGE("Null C2Buffer");
- return Status::BAD_VALUE;
- }
- status = objcpy(&dBuffer, *sBuffer, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- }
-
- status = createParamsBlob(&d->configUpdate, s.configUpdate);
- if (status != Status::OK) {
- return status;
- }
-
- d->infoBuffers.resize(s.infoBuffers.size());
- i = 0;
- for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
- InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
- if (!sInfoBuffer) {
- ALOGE("Null C2InfoBuffer");
- return Status::BAD_VALUE;
- }
- status = objcpy(&dInfoBuffer, *sInfoBuffer, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- }
-
- return status;
-}
-
-} // unnamed namespace
-
-// std::list<std::unique_ptr<C2Work>> -> WorkBundle
-// TODO: Connect with Bufferpool
-Status objcpy(WorkBundle* d, const std::list<std::unique_ptr<C2Work>>& s) {
- Status status = Status::OK;
-
- std::vector<BaseBlock> baseBlocks;
- std::map<const C2Handle*, uint32_t> baseBlockIndices;
- d->works.resize(s.size());
- size_t i = 0;
- for (const std::unique_ptr<C2Work>& sWork : s) {
- Work &dWork = d->works[i++];
- if (!sWork) {
- ALOGW("Null C2Work encountered.");
- continue;
- }
- status = objcpy(&dWork.input, sWork->input,
- &baseBlocks, &baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- if (sWork->worklets.size() == 0) {
- ALOGW("Work with no worklets.");
- } else {
- if (sWork->worklets.size() > 1) {
- ALOGW("Work with multiple worklets. "
- "Only the first worklet will be marshalled.");
- }
- if (!sWork->worklets.front()) {
- ALOGE("Null worklet encountered.");
- return Status::BAD_VALUE;
- }
-
- // Parcel the first worklet.
- const C2Worklet &sWorklet = *sWork->worklets.front();
- Worklet &dWorklet = dWork.worklet;
-
- dWorklet.tunings.resize(sWorklet.tunings.size());
- size_t j = 0;
- for (const std::unique_ptr<C2Tuning>& sTuning : sWorklet.tunings) {
- status = createParamsBlob(
- &dWorklet.tunings[j++],
- std::vector<C2Param*>
- { reinterpret_cast<C2Param*>(sTuning.get()) });
- if (status != Status::OK) {
- return status;
- }
- }
-
- dWorklet.failures.resize(sWorklet.failures.size());
- j = 0;
- for (const std::unique_ptr<C2SettingResult>& sFailure :
- sWorklet.failures) {
- if (!sFailure) {
- ALOGE("Null C2SettingResult");
- return Status::BAD_VALUE;
- }
- status = objcpy(&dWorklet.failures[j++], *sFailure);
- if (status != Status::OK) {
- return status;
- }
- }
-
- status = objcpy(&dWorklet.output, sWorklet.output,
- &baseBlocks, &baseBlockIndices);
- if (status != Status::OK) {
- return status;
- }
- }
- dWork.workletProcessed = sWork->workletsProcessed > 0;
- dWork.result = static_cast<Status>(sWork->result);
- }
-
- d->baseBlocks = baseBlocks;
-
- return Status::OK;
-}
-
-namespace /* unnamed */ {
-
-// hidl_handle -> C2Fence
-// Note: File descriptors are not duplicated. The original file descriptor must
-// not be closed before the transaction is complete.
-c2_status_t objcpy(C2Fence* d, const hidl_handle& s) {
- // TODO: Implement.
- (void)s;
- *d = C2Fence();
- return C2_OK;
-}
-
-// Buffer -> C2Buffer
-// Note: The native handles will be cloned.
-c2_status_t objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
- const hidl_vec<BaseBlock>& baseBlocks) {
- c2_status_t status;
-
- // First, construct C2Buffer with blocks from s.blocks.
- *d = nullptr;
-
- // TODO: Only buffers with 1 block are supported.
- if (s.blocks.size() == 1) {
- // Obtain the BaseBlock.
- const Block &sBlock = s.blocks[0];
- if (sBlock.index >= baseBlocks.size()) {
- ALOGE("Index into baseBlocks is out of range.");
- return C2_BAD_VALUE;
- }
- const BaseBlock &sBaseBlock = baseBlocks[sBlock.index];
-
- // Parse meta.
- std::vector<C2Param*> sBlockMeta;
- status = parseParamsBlob(&sBlockMeta, sBlock.meta);
- if (status != C2_OK) {
- ALOGE("Invalid block params blob.");
- return C2_BAD_VALUE;
- }
-
- // Copy fence.
- C2Fence dFence;
- status = objcpy(&dFence, sBlock.fence);
-
- // Construct a block.
- switch (sBaseBlock.type) {
- case BaseBlock::Type::NATIVE: {
- const native_handle_t* sHandle = sBaseBlock.nativeBlock;
- if (sHandle == nullptr) {
- ALOGE("Null native handle in a block.");
- return C2_BAD_VALUE;
- }
- sHandle = native_handle_clone(sHandle);
- if (sHandle == nullptr) {
- ALOGE("Cannot clone native handle.");
- return C2_NO_MEMORY;
- }
- const C2Handle *sC2Handle =
- reinterpret_cast<const C2Handle*>(sHandle);
-
- // Currently, there are only 2 types of C2Allocation: ion and
- // gralloc.
- if (C2AllocatorIon::isValid(sC2Handle)) {
- // Check the block meta. It should have exactly 1 C2Info:
- // C2Hidl_RangeInfo.
- if ((sBlockMeta.size() != 1) || !sBlockMeta[0]) {
- ALOGE("Invalid block metadata for ion block.");
- return C2_BAD_VALUE;
- }
- if (sBlockMeta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
- ALOGE("Invalid block metadata for ion block: range.");
- return C2_BAD_VALUE;
- }
- C2Hidl_RangeInfo *rangeInfo =
- reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
-
- std::shared_ptr<C2Allocator> allocator;
- c2_status_t status = GetCodec2PlatformAllocatorStore(
- )->fetchAllocator(
- C2PlatformAllocatorStore::ION,
- &allocator);
- if (status != C2_OK) {
- ALOGE("Cannot fetch platform linear allocator.");
- return status;
- }
- std::shared_ptr<C2LinearAllocation> allocation;
- status = allocator->priorLinearAllocation(
- sC2Handle, &allocation);
- if (status != C2_OK) {
- ALOGE("Error constructing linear allocation.");
- return status;
- } else if (!allocation) {
- ALOGE("Null linear allocation.");
- return C2_BAD_VALUE;
- }
- std::shared_ptr<C2LinearBlock> block =
- _C2BlockFactory::CreateLinearBlock(allocation);
- if (!block) {
- ALOGE("Cannot create a block.");
- return C2_BAD_VALUE;
- }
- *d = C2Buffer::CreateLinearBuffer(block->share(
- rangeInfo->offset, rangeInfo->length, dFence));
- if (!(*d)) {
- ALOGE("Cannot create a linear buffer.");
- return C2_BAD_VALUE;
- }
- } else if (C2AllocatorGralloc::isValid(sC2Handle)) {
- // Check the block meta. It should have exactly 1 C2Info:
- // C2Hidl_RectInfo.
- if ((sBlockMeta.size() != 1) || !sBlockMeta[0]) {
- ALOGE("Invalid block metadata for graphic block.");
- return C2_BAD_VALUE;
- }
- if (sBlockMeta[0]->size() != sizeof(C2Hidl_RectInfo)) {
- ALOGE("Invalid block metadata for graphic block: crop rect.");
- return C2_BAD_VALUE;
- }
- C2Hidl_RectInfo *rectInfo =
- reinterpret_cast<C2Hidl_RectInfo*>(sBlockMeta[0]);
-
- std::shared_ptr<C2Allocator> allocator;
- c2_status_t status = GetCodec2PlatformAllocatorStore(
- )->fetchAllocator(
- C2PlatformAllocatorStore::GRALLOC,
- &allocator);
- if (status != C2_OK) {
- ALOGE("Cannot fetch platform graphic allocator.");
- return status;
- }
-
- std::shared_ptr<C2GraphicAllocation> allocation;
- status = allocator->priorGraphicAllocation(
- sC2Handle, &allocation);
- if (status != C2_OK) {
- ALOGE("Error constructing graphic allocation.");
- return status;
- } else if (!allocation) {
- ALOGE("Null graphic allocation.");
- return C2_BAD_VALUE;
- }
- std::shared_ptr<C2GraphicBlock> block =
- _C2BlockFactory::CreateGraphicBlock(allocation);
- if (!block) {
- ALOGE("Cannot create a block.");
- return C2_BAD_VALUE;
- }
- *d = C2Buffer::CreateGraphicBuffer(block->share(
- C2Rect(rectInfo->width, rectInfo->height,
- rectInfo->left, rectInfo->top),
- dFence));
- if (!(*d)) {
- ALOGE("Cannot create a graphic buffer.");
- return C2_BAD_VALUE;
- }
- } else {
- ALOGE("Unknown handle type.");
- return C2_BAD_VALUE;
- }
- break;
- }
- case BaseBlock::Type::POOLED: {
- // TODO: Implement. Use BufferPool.
- return C2_OMITTED;
- }
- default:
- ALOGE("Invalid BaseBlock type.");
- return C2_BAD_VALUE;
- }
- } else {
- ALOGE("Currently a buffer must contain exactly 1 block.");
- return C2_BAD_VALUE;
- }
-
- // Parse info
- std::vector<C2Param*> params;
- status = parseParamsBlob(¶ms, s.info);
- if (status != C2_OK) {
- ALOGE("Invalid buffer params blob.");
- return status;
- }
- for (C2Param* param : params) {
- if (param == nullptr) {
- ALOGE("Null buffer param encountered.");
- return C2_BAD_VALUE;
- }
- std::shared_ptr<C2Param> c2param(
- C2Param::Copy(*param).release());
- if (!c2param) {
- ALOGE("Invalid buffer param inside a blob.");
- return C2_BAD_VALUE;
- }
- status = (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
- if (status != C2_OK) {
- ALOGE("C2Buffer::setInfo failed().");
- return C2_BAD_VALUE;
- }
- }
-
- return C2_OK;
-}
-
-// FrameData -> C2FrameData
-c2_status_t objcpy(C2FrameData* d, const FrameData& s,
- const hidl_vec<BaseBlock>& baseBlocks) {
- c2_status_t status;
- d->flags = static_cast<C2FrameData::flags_t>(s.flags);
- objcpy(&d->ordinal, s.ordinal);
- d->buffers.clear();
- d->buffers.reserve(s.buffers.size());
- for (const Buffer& sBuffer : s.buffers) {
- std::shared_ptr<C2Buffer> dBuffer;
- status = objcpy(&dBuffer, sBuffer, baseBlocks);
- if (status != C2_OK) {
- return status;
- }
- d->buffers.emplace_back(dBuffer);
- }
-
- std::vector<C2Param*> params;
- status = parseParamsBlob(¶ms, s.configUpdate);
- if (status != C2_OK) {
- ALOGE("Failed to parse frame data params.");
- return status;
- }
- d->configUpdate.clear();
- for (C2Param* param : params) {
- d->configUpdate.emplace_back(C2Param::Copy(*param));
- if (!d->configUpdate.back()) {
- ALOGE("Unexpected error while parsing frame data params.");
- return C2_BAD_VALUE;
- }
- }
-
- // TODO: Implement this once C2InfoBuffer has constructors.
- d->infoBuffers.clear();
- return C2_OK;
-}
-
-} // unnamed namespace
-
-// WorkBundle -> std::list<std::unique_ptr<C2Work>>
-// TODO: Connect with Bufferpool
-c2_status_t objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
- c2_status_t status;
- d->clear();
- for (const Work& sWork : s.works) {
- d->emplace_back(std::make_unique<C2Work>());
- C2Work& dWork = *d->back();
-
- // input
- status = objcpy(&dWork.input, sWork.input, s.baseBlocks);
- if (status != C2_OK) {
- ALOGE("Error constructing C2Work's input.");
- return C2_BAD_VALUE;
- }
-
- // worklet(s)
- // TODO: Currently, tunneling is not supported.
- if (sWork.workletProcessed) {
- dWork.worklets.clear();
- dWork.workletsProcessed = 1;
-
- const Worklet &sWorklet = sWork.worklet;
- std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
-
- // tunings
- dWorklet->tunings.clear();
- dWorklet->tunings.reserve(sWorklet.tunings.size());
- for (const Params& sTuning : sWorklet.tunings) {
- std::vector<C2Param*> dParams;
- status = parseParamsBlob(&dParams, sTuning);
- if (status != C2_OK) {
- ALOGE("Failed to parse C2Tuning in C2Worklet.");
- return C2_BAD_VALUE;
- }
- for (C2Param* param : dParams) {
- std::unique_ptr<C2Param> dParam = C2Param::Copy(*param);
- if (!dParam) {
- ALOGE("Null C2Tuning encountered while "
- "parsing C2Worklet.");
- return C2_BAD_VALUE;
- }
- dWorklet->tunings.emplace_back(
- std::unique_ptr<C2Tuning>(
- reinterpret_cast<C2Tuning*>(
- dParam.release())));
- }
- }
- // failures
- dWorklet->failures.clear();
- dWorklet->failures.reserve(sWorklet.failures.size());
- for (const SettingResult& sFailure : sWorklet.failures) {
- std::unique_ptr<C2SettingResult> dFailure;
- status = objcpy(&dFailure, sFailure);
- if (status != C2_OK) {
- ALOGE("Failed to create C2SettingResult in C2Worklet.");
- return C2_BAD_VALUE;
- }
- dWorklet->failures.emplace_back(std::move(dFailure));
- }
- // output
- status = objcpy(&dWorklet->output, sWorklet.output, s.baseBlocks);
- if (status != C2_OK) {
- ALOGE("Failed to create output C2FrameData.");
- return C2_BAD_VALUE;
- }
- dWork.worklets.emplace_back(std::move(dWorklet));
- } else {
- dWork.worklets.clear();
- dWork.workletsProcessed = 0;
- }
-
- // result
- dWork.result = static_cast<c2_status_t>(sWork.result);
- }
-
- return C2_OK;
-}
-
-// Params -> std::vector<C2Param*>
-c2_status_t parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
- // assuming blob is const here
- size_t size = blob.size();
- const uint8_t *data = blob.data();
- C2Param *p = nullptr;
-
- do {
- p = C2ParamUtils::ParseFirst(data, size);
- if (p) {
- params->emplace_back(p);
- size -= p->size();
- data += p->size();
- }
- } while (p);
-
- return size == 0 ? C2_OK : C2_BAD_VALUE;
-}
-
-namespace /* unnamed */ {
-
-/**
- * Concatenates a list of C2Params into a params blob.
- * \param[out] blob target blob
- * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- * not const)
- */
-template<typename T>
-Status _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
- // assuming the parameter values are const
- size_t size = 0;
- for (const auto &p : params) {
- size += p->size();
- }
- blob->resize(size);
- size_t ix = 0;
- for (const auto &p : params) {
- // NEVER overwrite even if param values (e.g. size) changed
- size_t paramSize = std::min(p->size(), size - ix);
-// memcpy(&blob[ix], &*p, paramSize);
- std::copy(
- reinterpret_cast<const uint8_t*>(&*p),
- reinterpret_cast<const uint8_t*>(&*p) + paramSize,
- &blob[ix]);
- ix += paramSize;
- }
- blob->resize(ix);
- return ix == size ? Status::OK : Status::CORRUPTED;
-}
-
-} // unnamed namespace
-
-// std::vector<const C2Param*> -> Params
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<const C2Param*> ¶ms) {
- return _createParamsBlob(blob, params);
-}
-
-// std::vector<C2Param*> -> Params
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<C2Param*> ¶ms) {
- return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::unique_ptr<C2Param>> -> Params
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::unique_ptr<C2Param>> ¶ms) {
- return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::unique_ptr<C2Tuning>> -> Params
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
- return _createParamsBlob(blob, params);
-}
-
-// std::vector<std::shared_ptr<const C2Info>> -> Params
-Status createParamsBlob(
- hidl_vec<uint8_t> *blob,
- const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
- return _createParamsBlob(blob, params);
-}
-
-// Params -> std::vector<std::unique_ptr<C2Param>>
-c2_status_t copyParamsFromBlob(
- std::vector<std::unique_ptr<C2Param>>* params,
- Params blob) {
- std::vector<C2Param*> paramPointers;
- c2_status_t status = parseParamsBlob(¶mPointers, blob);
- if (status != C2_OK) {
- ALOGE("copyParamsFromBlob -- blob parsing failed.");
- return status;
- }
- params->resize(paramPointers.size());
- size_t i = 0;
- for (C2Param* const& paramPointer : paramPointers) {
- if (!paramPointer) {
- ALOGE("copyParamsFromBlob -- corrupted params blob.");
- return C2_BAD_VALUE;
- }
- (*params)[i++] = C2Param::Copy(*paramPointer);
- }
- return C2_OK;
-}
-
-// Params -> update std::vector<std::unique_ptr<C2Param>>
-c2_status_t updateParamsFromBlob(
- const std::vector<C2Param*>& params,
- const Params& blob) {
- std::unordered_map<uint32_t, C2Param*> index2param;
- for (C2Param* const& param : params) {
- if (!param) {
- ALOGE("updateParamsFromBlob -- corrupted input params.");
- return C2_BAD_VALUE;
- }
- if (index2param.find(param->index()) == index2param.end()) {
- index2param.emplace(param->index(), param);
- }
- }
-
- std::vector<C2Param*> paramPointers;
- c2_status_t status = parseParamsBlob(¶mPointers, blob);
- if (status != C2_OK) {
- ALOGE("updateParamsFromBlob -- blob parsing failed.");
- return status;
- }
-
- for (C2Param* const& paramPointer : paramPointers) {
- if (!paramPointer) {
- ALOGE("updateParamsFromBlob -- corrupted param in blob.");
- return C2_BAD_VALUE;
- }
- decltype(index2param)::iterator i = index2param.find(
- paramPointer->index());
- if (i == index2param.end()) {
- ALOGW("updateParamsFromBlob -- unseen param index.");
- continue;
- }
- if (!i->second->updateFrom(*paramPointer)) {
- ALOGE("updateParamsFromBlob -- mismatching sizes: "
- "%u vs %u (index = %u).",
- static_cast<unsigned>(params.size()),
- static_cast<unsigned>(paramPointer->size()),
- static_cast<unsigned>(i->first));
- return C2_BAD_VALUE;
- }
- }
- return C2_OK;
-}
-
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/Android.bp b/media/libstagefright/codec2/hidl/interfaces/1.0/Android.bp
deleted file mode 100644
index e75ef24..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/Android.bp
+++ /dev/null
@@ -1,56 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_package_root {
- name: "vendor.google.media.c2",
- path: "frameworks/av/media/libstagefright/codec2/hidl/interfaces",
-}
-
-hidl_interface {
- name: "vendor.google.media.c2@1.0",
- root: "vendor.google.media.c2",
- vndk: {
- enabled: true,
- },
- srcs: [
- "types.hal",
- "IComponent.hal",
- "IComponentInterface.hal",
- "IComponentListener.hal",
- "IComponentStore.hal",
- "IConfigurable.hal",
- "IInputSurface.hal",
- "IInputSurfaceConnection.hal",
- ],
- interfaces: [
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.common@1.0",
- "android.hardware.media.bufferpool@1.0",
- "android.hardware.media.omx@1.0",
- "android.hardware.media@1.0",
- "android.hidl.base@1.0",
- ],
- types: [
- "Block",
- "BlockId",
- "Buffer",
- "FieldDescriptor",
- "FieldId",
- "FieldSupportedValues",
- "FieldSupportedValuesQuery",
- "FieldSupportedValuesQueryResult",
- "FieldType",
- "FrameData",
- "InfoBuffer",
- "ParamDescriptor",
- "ParamField",
- "ParamFieldValues",
- "SettingResult",
- "Status",
- "StructDescriptor",
- "Work",
- "WorkOrdinal",
- "Worklet",
- ],
- gen_java: false,
-}
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponent.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IComponent.hal
deleted file mode 100644
index b1b4fc2..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponent.hal
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
-import android.hardware.media.omx@1.0::IGraphicBufferSource;
-
-import IConfigurable;
-import IComponentInterface;
-import IComponentListener;
-import IInputSurface;
-
-/**
- * Interface for a Codec 2.0 component corresponding to API level 1.0 or
- * below. Components have two states: stopped and running. The running
- * state has three sub-states: executing, tripped and error.
- */
-interface IComponent extends IComponentInterface {
-
- // METHODS AVAILABLE WHEN RUNNING
- // =========================================================================
-
- /**
- * Queues up work for the component.
- *
- * This method must be supported in running (including tripped) states.
- *
- * This method must return within 1ms
- *
- * It is acceptable for this method to return OK and return an error value
- * using the onWorkDone() callback.
- *
- * @param workBundle WorkBundle object containing Works to queue to the
- * component.
- * @return status Status of the call, which may be
- * - OK - Works in \p workBundle were successfully queued.
- * - BAD_INDEX - Some component(s) in some Work do(es) not exist.
- * - CANNOT_DO - The components are not tunneled.
- * - NO_MEMORY - Not enough memory to queue \p workBundle.
- * - CORRUPTED - Some unknown error prevented queuing the Works.
- * (unexpected).
- */
- queue(WorkBundle workBundle) generates (Status status);
-
- /**
- * Discards and abandons any pending work for the component.
- *
- * This method must be supported in running (including tripped) states.
- *
- * This method must return within 5ms.
- *
- * Work that could be immediately abandoned/discarded must be returned in
- * \p flushedWorks; this can be done in an arbitrary order.
- *
- * Work that could not be abandoned or discarded immediately must be marked
- * to be discarded at the earliest opportunity, and must be returned via
- * the onWorkDone() callback. This must be completed within 500ms.
- *
- * @return status Status of the call, which may be
- * - OK - The component has been successfully flushed.
- * - TIMED_OUT - The flush could not be completed within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented flushing from
- * completion. (unexpected)
- * @return flushedWorkBundle WorkBundle object containing flushed Works.
- */
- flush(
- ) generates (
- Status status,
- WorkBundle flushedWorkBundle
- );
-
- /**
- * Drains the component, and optionally downstream components. This is a
- * signalling method; as such it does not wait for any work completion.
- *
- * Marks last work item as "drain-till-here", so component is notified not
- * to wait for further work before it processes work already queued. This
- * method can also be used to set the end-of-stream flag after work has been
- * queued. Client can continue to queue further work immediately after this
- * method returns.
- *
- * This method must be supported in running (including tripped) states.
- *
- * This method must return within 1ms.
- *
- * Work that is completed must be returned via the onWorkDone() callback.
- *
- * @param withEos Whether to drain the component with marking end-of-stream.
- * @return status Status of the call, which may be
- * - OK - The drain request has been successfully recorded.
- * - TIMED_OUT - The flush could not be completed within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented flushing from completion.
- * (unexpected)
- */
- drain(bool withEos) generates (Status status);
-
- /**
- * Starts using a persistent input surface for a component.
- *
- * The component must be in running state.
- *
- * @param surface A persistent input surface to use for codec input.
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - CANNOT_DO - The component does not support an input surface.
- * - BAD_STATE - Component is not in running state.
- * - DUPLICATE - The component is already connected to an input surface.
- * - REFUSED - The input surface is already in use.
- * - NO_MEMORY - Not enough memory to start the component.
- * - TIMED_OUT - The component could not be connected within the time
- * limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented connecting the component.
- * (unexpected)
- */
- connectToInputSurface(IInputSurface surface) generates (Status status);
-
- /**
- * Starts using a persistent OMX input surface for a component.
- *
- * The component must be in running state.
- *
- * @param producer Producer component of an OMX persistent input surface.
- * @param source Source component of an OMX persistent input surface.
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - CANNOT_DO - The component does not support an input surface.
- * - BAD_STATE - Component is not in running state.
- * - DUPLICATE - The component is already connected to an input surface.
- * - REFUSED - The input surface is already in use.
- * - NO_MEMORY - Not enough memory to start the component.
- * - TIMED_OUT - The component could not be connected within the time
- * limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented connecting the component.
- * (unexpected)
- */
- connectToOmxInputSurface(
- IGraphicBufferProducer producer,
- IGraphicBufferSource source
- ) generates (Status status);
-
- /**
- * Stops using an input surface.
- *
- * This call is used for both Codec 2.0 and OMX input surfaces.
- *
- * The component must be in running state.
- *
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - CANNOT_DO - The component does not support an input surface.
- * - BAD_STATE - Component is not in running state.
- * - NOT_FOUND - The component is not connected to an input surface.
- * - TIMED_OUT - The component could not be connected within the time
- * limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented connecting the component.
- * (unexpected)
- */
- disconnectFromInputSurface() generates (Status Status);
-
- /**
- * Creates a local block pool backed by the given allocator and returns its
- * identifier.
- *
- * This call must return within 100 msec.
- *
- * @param allocatorId The Codec 2.0 allocator ID
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - NO_MEMORY - Not enough memory to create the pool.
- * - BAD_VALUE - Invalid allocator.
- * - TIMED_OUT - The pool could not be created within the time
- * limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented creating the pool.
- * (unexpected)
- * @return blockPoolId The Codec 2.0 blockpool ID for the created pool.
- * @return configurable Configuration interface for the created pool.
- */
- createBlockPool(uint32_t allocatorId) generates (
- Status status,
- uint64_t blockPoolId,
- IConfigurable configurable
- );
-
- // STATE CHANGE METHODS
- // =========================================================================
-
- /**
- * Starts the component.
- *
- * This method must be supported in stopped state as well as tripped state.
- *
- * If the return value is OK, the component must be in the running state.
- * If the return value is BAD_STATE or DUPLICATE, no state change is
- * expected as a response to this call.
- * Otherwise, the component must be in the stopped state.
- *
- * If a component is in the tripped state and start() is called while the
- * component configuration still results in a trip, start must succeed and
- * a new onTripped callback must be used to communicate the configuration
- * conflict that results in the new trip.
- *
- * This method must return within 500ms.
- *
- * @return status Status of the call, which may be
- * - OK - The component has started successfully.
- * - BAD_STATE - Component is not in stopped or tripped state.
- * - DUPLICATE - When called during another start call from another
- * thread.
- * - NO_MEMORY - Not enough memory to start the component.
- * - TIMED_OUT - The component could not be started within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented starting the component.
- * (unexpected)
- */
- start() generates (Status status);
-
- /**
- * Stops the component.
- *
- * This method must be supported in running (including tripped) state.
- *
- * This method must return withing 500ms.
- *
- * Upon this call, all pending work must be abandoned.
- * If the return value is BAD_STATE or DUPLICATE, no state change is
- * expected as a response to this call.
- * For all other return values, the component must be in the stopped state.
- *
- * This does not alter any settings and tunings that may have resulted in a
- * tripped state.
- *
- * @return status Status of the call, which may be
- * - OK - The component has stopped successfully.
- * - BAD_STATE - Component is not in running state.
- * - DUPLICATE - When called during another stop call from another thread.
- * - TIMED_OUT - The component could not be stopped within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented starting the component.
- * (unexpected)
- */
- stop() generates (Status status);
-
- /**
- * Resets the component.
- *
- * This method must be supported in all (including tripped) states other
- * than released.
- *
- * This method must be supported during any other blocking call.
- *
- * This method must return withing 500ms.
- *
- * After this call returns all work must have been abandoned, all references
- * must have been released.
- *
- * If the return value is BAD_STATE or DUPLICATE, no state change is
- * expected as a response to this call.
- * For all other return values, the component shall be in the stopped state.
- *
- * This brings settings back to their default - "guaranteeing" no tripped
- * state.
- *
- * @return status Status of the call, which may be
- * - OK - The component has been reset.
- * - BAD_STATE - Component is in released state.
- * - DUPLICATE - When called during another reset call from another
- * thread.
- * - TIMED_OUT - The component could not be reset within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented resetting the component.
- * (unexpected)
- */
- reset() generates (Status status);
-
- /**
- * Releases the component.
- *
- * This method must be supported in stopped state.
- *
- * This method must return withing 500ms. Upon return all references must
- * be abandoned.
- *
- * @return status Status of the call, which may be
- * - OK - The component has been released.
- * - BAD_STATE - The component is running.
- * - DUPLICATE - The component is already released.
- * - TIMED_OUT - The component could not be released within the time
- * limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented releasing the component.
- * (unexpected)
- */
- release() generates (Status status);
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentInterface.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentInterface.hal
deleted file mode 100644
index 7014998..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentInterface.hal
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-import IConfigurable;
-
-/**
- * Component interface object. This object contains all of the configuration of
- * a potential or actual component. It can be created and used independently of
- * an actual Codec 2.0 component instance to query support and parameters for
- * various component settings and configurations for a potential component.
- * Actual components also expose this interface.
- */
-interface IComponentInterface extends IConfigurable {
- /*
- * There are no additional methods to IConfigurable interface.
- *
- * Component interfaces have no states.
- *
- * The name of the component or component interface object is a unique name
- * for that component or component interface 'class'; however, multiple
- * instances of that component must have the same name.
- */
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentListener.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentListener.hal
deleted file mode 100644
index d1a681a..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentListener.hal
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-/**
- * This callback interface is used for handling notifications from IComponent.
- */
-interface IComponentListener {
-
- /**
- * Notify the listener that some works have been completed.
- */
- oneway onWorkDone(WorkBundle workBundle);
-
- /**
- * Notify the listener that the component is tripped.
- */
- oneway onTripped(vec<SettingResult> settingResults);
-
- /**
- * Notify the listener of an error.
- *
- * @param status The error type. \p status may be `OK`, which means that an
- * error has occurred, but the error type is unknown.
- * @param errorCode Additional error code. The framework may not recognize
- * this.
- */
- oneway onError(Status status, uint32_t errorCode);
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentStore.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentStore.hal
deleted file mode 100644
index eae5b72..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IComponentStore.hal
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-import android.hardware.media.bufferpool@1.0::IClientManager;
-import IComponentInterface;
-import IComponentListener;
-import IComponent;
-import IConfigurable;
-import IInputSurface;
-
-interface IComponentStore extends IConfigurable {
-
- /**
- * Creates a component by name.
- *
- * This method must return within 100ms.
- *
- * @param name Name of the component to create. This should match one of the
- * names returned by listComponents().
- * @param listener The component listener to use for the component.
- * @param pool The buffer pool client manager of the component listener.
- * This must be null if the listener process does not own a buffer pool.
- * @return status Status of the call, which may be
- * - OK - The component was created successfully.
- * - NOT_FOUND - There is no component with the given name.
- * - NO_MEMORY - Not enough memory to create the component.
- * - TIMED_OUT - The component could not be created within the time limit.
- * (unexpected)
- * - CORRUPTED - Some unknown error prevented the creation of the
- * component. (unexpected)
- * @return comp The created component if `Status = OK`.
- */
- createComponent(
- string name,
- IComponentListener listener,
- IClientManager pool
- ) generates (
- Status status,
- IComponent comp
- );
-
- /**
- * Creates a component interface by name.
- *
- * This method must return within 100ms.
- *
- * @param name Name of the component interface to create. This should match
- * one of the names returned by listComponents().
- * @return status Status of the call, which may be
- * - OK - The component interface was created successfully.
- * - NOT_FOUND - There is no component interface with the given name.
- * - NO_MEMORY - Not enough memory to create the component interface.
- * - TIMED_OUT - The component interface could not be created within the
- * time limit. (unexpected)
- * - CORRUPTED - Some unknown error prevented the creation of the
- * component interface. (unexpected)
- * @return compIntf The created component interface if `Status = OK`.
- */
- createInterface(
- string name
- ) generates (
- Status status,
- IComponentInterface compIntf
- );
-
- /**
- * Component traits.
- */
- struct ComponentTraits {
- /**
- * Name of the component.
- */
- string name;
-
- enum Domain : uint32_t {
- AUDIO,
- VIDEO,
- OTHER = 0xffffffff,
- };
- /**
- * Component domain. The framework may not recognize `OTHER`.
- */
- Domain domain;
- /**
- * If #domain is `OTHER`, #domainOther can be used to provide additional
- * information. Otherwise, #domainOther is ignored. The framework may
- * not inspect this value.
- */
- uint32_t domainOther;
-
- enum Kind : uint32_t {
- DECODER,
- ENCODER,
- OTHER = 0xffffffff,
- };
- /**
- * Component kind. The framework may not recognize `OTHER`.
- */
- Kind kind;
- /**
- * If #kind is `OTHER`, #kindOther can be used to provide additional
- * information. Otherwise, #kindOther is ignored. The framework may not
- * inspect this value.
- */
- uint32_t kindOther;
-
- /**
- * Rank used by MediaCodecList to determine component ordering. Lower
- * value means higher priority.
- */
- uint32_t rank;
-
- /**
- * Media type.
- */
- string mediaType;
-
- /**
- * Aliases for component name for backward compatibility.
- *
- * \note Multiple components can have the same alias (but not the same
- * component name) as long as their media types differ.
- */
- vec<string> aliases;
- };
-
- /**
- * Returns the list of components supported by this component store.
- *
- * This method must return within 500ms.
- *
- * @return traits List of component traits for all components supported by this store in no
- * particular order.
- */
- listComponents() generates (vec<ComponentTraits> traits);
-
- /**
- * Creates a persistent input surface that can be used as an input surface
- * for any IComponent instance
- *
- * This method must return within 100ms.
- *
- * @return surface A persistent input surface
- */
- createInputSurface() generates (IInputSurface surface);
-
- /**
- * Returns a list of StructDescriptor object for a set of requested
- * structures that this store is aware of.
- *
- * This operation must be performed at best effort, e.g. the component
- * store must simply ignore all struct indices that it is not aware of.
- *
- * @param indices struct indices to return des
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - NOT_FOUND - Some indices were not known.
- * - NO_MEMORY - Not enough memory to complete this method.
- * @return structs List of StructDescriptor objects.
- */
- getStructDescriptors(
- vec<ParamIndex> indices
- ) generates (
- Status status,
- vec<StructDescriptor> structs
- );
-
- /**
- * Returns information required for using BufferPool API in buffer passing.
- * If the returned pool is not null, the client can call registerSender() to
- * register its IAccessor instance, hence allowing the client to send
- * buffers to components hosted by this process.
- *
- * @return pool If the component store supports receiving buffers via
- * BufferPool API, \p pool must be a valid `IClientManager` instance.
- * Otherwise, \p pool must be null.
- */
- getPoolClientManager(
- ) generates (
- IClientManager pool
- );
-
- /**
- * The store must copy the contents of \p src into \p dst without changing
- * the format of \p dst.
- *
- * @param src Source buffer.
- * @param dst Destination buffer.
- * @return status Status of the call, which may be
- * - OK - The copy is successful.
- * - CANNOT_DO - \p src and \p dst are not compatible.
- * - REFUSED - No permission to copy.
- * - CORRUPTED - The copy cannot be done. (unexpected)
- */
- copyBuffer(Buffer src, Buffer dst) generates (Status status);
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IConfigurable.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IConfigurable.hal
deleted file mode 100644
index 83447ad..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IConfigurable.hal
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-/**
- * Generic configuration interface used by all configurable Codec 2.0
- * components.
- *
- * This interface must be supported in all states of the inheriting
- * object, and must not change the state of the inheriting object.
- */
-interface IConfigurable {
- /**
- * Returns the name of this object. This must match the name that was
- * supplied during the creation of the object.
- *
- * @return name Name of this object.
- */
- getName() generates (string name);
-
- /**
- * Queries a set of parameters from the object. Querying is performed at
- * best effort: the object must query all supported parameters and skip
- * unsupported ones, or parameters that could not be allocated. Any errors
- * are communicated in the return value.
- *
- * \note Parameter values do not depend on the order of query.
- *
- * This method must return within 1ms if \p mayBlock is DONT_BLOCK, and
- * within 5ms otherwise.
- *
- * @param indices List of param indices for params to be queried.
- * @param mayBlock Whether this call may block or not.
- * @return status Status of the call, which may be
- * - OK - All parameters could be queried.
- * - BAD_INDEX - All supported parameters could be queried, but some
- * parameters were not supported.
- * - NO_MEMORY - Could not allocate memory for a supported parameter.
- * - BLOCKING - Querying some parameters requires blocking.
- * - CORRUPTED - Some unknown error prevented the querying of the
- * parameters. (unexpected)
- * @return params List of params queried corresponding to \p indices.
- */
- query(
- vec<ParamIndex> indices,
- bool mayBlock
- ) generates (
- Status status,
- Params params
- );
-
- /**
- * Sets a set of parameters for the object. Tuning is performed at best
- * effort: the object must update all supported configuration at best
- * effort and skip unsupported parameters. Any errors are communicated in
- * the return value and in \p failures.
- *
- * \note Parameter tuning DOES depend on the order of the tuning parameters.
- * E.g. some parameter update may allow some subsequent parameter update.
- *
- * This method must return within 1ms if \p mayBlock is false, and within
- * 5ms otherwise.
- *
- * @param inParams Requested parameter updates.
- * @param mayBlock Whether this call may block or not.
- * @return status Status of the call, which may be
- * - OK - All parameters could be updated successfully.
- * - BAD_INDEX - All supported parameters could be updated successfully,
- * but some parameters were not supported.
- * - NO_MEMORY - Some supported parameters could not be updated
- * successfully because they contained unsupported values.
- * These are returned in \p failures.
- * - BLOCKING - Setting some parameters requires blocking.
- * - CORRUPTED - Some unknown error prevented the update of the
- * parameters. (unexpected)
- * @return failures List of parameter failures.
- * @return outParams Resulting values for the configured parameters.
- */
- config(
- Params inParams,
- bool mayBlock
- ) generates (
- Status status,
- vec<SettingResult> failures,
- Params outParams
- );
-
- // REFLECTION MECHANISM
- // =========================================================================
-
- /**
- * Returns a selected range of the set of supported parameters.
- *
- * The set of supported parameters are represented in a vector with a
- * start index of 0, and the selected range are indices into this vector.
- * Fewer than \p count parameters are returned if the selected range is
- * not fully/not at all part of the available vector indices.
- *
- * This method must return within 1ms.
- *
- * @param start start index of selected range
- * @param count size of the selected
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - NO_MEMORY - Not enough memory to complete this method.
- * @return params Vector containing the selected range of supported
- * parameters.
- */
- querySupportedParams(
- uint32_t start,
- uint32_t count
- ) generates (
- Status status,
- vec<ParamDescriptor> params
- );
-
- /**
- * Retrieves the supported values for the queried fields.
- *
- * Upon return the object must fill in the supported
- * values for the fields listed as well as a status for each field.
- * Object shall process all fields queried even if some queries fail.
- *
- * This method must return within 1ms if \p mayBlock is false, and within
- * 5ms otherwise.
- *
- * @param inFields Vector of field queries.
- * @param mayBlock Whether this call may block or not.
- * @return status Status of the call, which may be
- * - OK - The operation completed successfully.
- * - BLOCKING - Querying some parameters requires blocking.
- * - NO_MEMORY - Not enough memory to complete this method.
- * - BAD_INDEX - At least one field was not recognized as a component
- * field.
- * @return outFields Vector containing supported values and query result
- * for the selected fields.
- */
- querySupportedValues(
- vec<FieldSupportedValuesQuery> inFields,
- bool mayBlock
- ) generates (
- Status status,
- vec<FieldSupportedValuesQueryResult> outFields
- );
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurface.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurface.hal
deleted file mode 100644
index 79dd65f..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurface.hal
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
-
-import IConfigurable;
-import IInputSurfaceConnection;
-
-/**
- * Input surface that can be configured for the IComponent.
- */
-interface IInputSurface extends IGraphicBufferProducer {
-
- /**
- * Connects this input surface to a component.
- *
- * This call must return within 100 ms.
- *
- * @param component The component to connect to. This must have type
- * IComponent.
- * @return status Status of the call, which may be
- * - OK - The operation succeeded.
- * - BAD_STATE - The component is in running state.
- * - DUPLICATE - The surface is already connected to a component.
- * - NO_MEMORY - Could not allocate memory to connect to the component.
- * - CORRUPTED - Some unknown error prevented the connection. (unexpected)
- * @return connection Connection object that is used to disconnect
- * from the component.
- */
- connectToComponent(
- interface component
- ) generates (
- Status status,
- IInputSurfaceConnection connection
- );
-
- /**
- * Returns the Codec 2.0 configuration object for this surface.
- *
- * @return configurable The configuration object for this surface.
- */
- getConfigurable() generates (IConfigurable configurable);
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurfaceConnection.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurfaceConnection.hal
deleted file mode 100644
index 4deabb9..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/IInputSurfaceConnection.hal
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-interface IInputSurfaceConnection {
-
- /**
- * Disconnects this input surface from the component.
- *
- * This call must return within 100 ms.
- *
- * @return status Status of the call, which may be
- * - OK - The operation succeeded.
- * - BAD_STATE - The component is not in running state.
- * - NOT_FOUND - The surface is not connected to a component.
- * - CORRUPTED - Some unknown error prevented the connection. (unexpected)
- */
- disconnect() generates (Status status);
-
-};
-
diff --git a/media/libstagefright/codec2/hidl/interfaces/1.0/types.hal b/media/libstagefright/codec2/hidl/interfaces/1.0/types.hal
deleted file mode 100644
index 65b7fec..0000000
--- a/media/libstagefright/codec2/hidl/interfaces/1.0/types.hal
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package vendor.google.media.c2@1.0;
-
-import android.hardware.media.bufferpool@1.0::BufferStatusMessage;
-
-enum Status : int32_t {
- /** operation completed successfully */
- OK = 0,
-
- // bad input
-
- /** argument has invalid value (user error) */
- BAD_VALUE = -22,
- /** argument uses invalid index (user error) */
- BAD_INDEX = -75,
- /** argument/index is valid but not possible */
- CANNOT_DO = -2147483646,
-
- // bad sequencing of events
-
- /** object already exists */
- DUPLICATE = -17,
- /** object not found */
- NOT_FOUND = -2,
- /** operation is not permitted in the current state */
- BAD_STATE = -38,
- /** operation would block but blocking is not permitted */
- BLOCKING = -9930,
-
- // bad environment
-
- /** not enough memory to complete operation */
- NO_MEMORY = -12,
- /** missing permission to complete operation */
- REFUSED = -1,
-
- /** operation did not complete within timeout */
- TIMED_OUT = -110,
-
- // missing functionality
-
- /** operation is not implemented/supported (optional only) */
- OMITTED = -74,
-
- // unknown fatal
-
- /** some unexpected error prevented the operation */
- CORRUPTED = -2147483648,
-
- // uninitialized
-
- /** status has not been initialized */
- NO_INIT = -19,
-};
-
-/**
- * Codec 2.0 parameter index
- */
-typedef uint32_t ParamIndex;
-
-/**
- * Codec 2.0 parameter structure
- *
- * The description of a Params is provided by supplying a ParamIndex to
- * IComponentStore::getStructDescriptors().
- */
-typedef vec<uint8_t> Params;
-
-/**
- * Struct uniquely specifying a field in an arbitrary parameter structure.
- */
-struct FieldId {
- /** Offset of the field in bytes */
- uint32_t offset;
- /** Size of the field in bytes */
- uint32_t size;
-};
-
-/**
- * Struct representing a location of a field in a parameter with a given index.
- */
-struct ParamField {
- /** Index of the parameter */
- ParamIndex index;
- /** Field identifier */
- FieldId fieldId;
-};
-
-/**
- * Struct describing basic properties of a parameter with a given index.
- */
-struct ParamDescriptor {
- /** Parameter index */
- ParamIndex index;
-
- enum Attrib : uint32_t {
- IS_REQUIRED = 1u << 0,
- IS_PERSISTENT = 1u << 1,
- };
- /** Parameter attributes */
- bitfield<Attrib> attrib;
-
- /** Parameter name */
- string name;
-
- /** index of other parameters that this parameter depends on */
- vec<ParamIndex> dependencies;
-};
-
-// Generic way to describe supported numeric values for Codec 2.0 interfaces.
-
-/**
- * An untyped value that can fit on 64 bits - the type of which is communicated
- * via a separate channel (FieldType).
- */
-typedef uint64_t PrimitiveValue;
-
-/*
- * Generic supported values for a field.
- *
- * This can be either a range or a set of values. The range can be linear or
- * geometric with clear minimum and maximum values, and can have an optional
- * step size or geometric ratio. Values can optionally represent flags.
- */
-struct FieldSupportedValues {
- struct Range {
- PrimitiveValue min;
- PrimitiveValue max;
- PrimitiveValue step;
- PrimitiveValue num;
- PrimitiveValue denom;
- };
-
- enum Type : int32_t {
- /** No supported values */
- EMPTY,
- /** Numeric range that can be continuous or discrete */
- RANGE,
- /** List of values */
- VALUES,
- /** List of flags that can be OR-ed */
- FLAGS,
- /** Other representations */
- OTHER = 0xffffffff,
- };
- /**
- * Type of the supported values. The framework may not recognize `OTHER`.
- */
- Type type;
- /**
- * Codec2.0 type code of the supported values.
- * * If #type is `OTHER`, #typeOther can be used to give more information.
- * In this case, the interpretation of this structure is
- * implementation-defined.
- * * For all other values of #type, #typeOther is not used.
- * The framework may not inspect this value.
- */
- int32_t typeOther;
-
- /*
- * If #type = EMPTY, #range and #value are unused.
- */
-
- /**
- * If #type = RANGE, #range will specify the range of possible values.
- *
- * The intended type of members of #range will be clear in the context where
- * FieldSupportedValues is used.
- */
- Range range;
-
- /**
- * If #type is `VALUES` or `FLAGS`, #value will list supported values.
- *
- * The intended type of components of #value will be clear in the context
- * where FieldSupportedValues is used.
- */
- vec<PrimitiveValue> values;
-};
-
-/**
- * Supported values for a specific field.
- *
- * This is a pair of the field specifier together with an optional supported
- * values object. This structure is used when reporting parameter configuration
- * failures and conflicts.
- */
-struct ParamFieldValues {
- /** the field or parameter */
- ParamField paramOrField;
-
- /**
- * optional supported values for the field if paramOrField specifies an
- * actual field that is numeric (non struct, blob or string). Supported
- * values for arrays (including string and blobs) describe the supported
- * values for each element (character for string, and bytes for blobs). It
- * is optional for read-only strings and blobs.
- */
- vec<FieldSupportedValues> values;
-};
-
-/**
- * Field descriptor.
- */
-struct FieldDescriptor {
-
- /** Field id */
- FieldId fieldId;
-
- /**
- * Possible types of a field.
- */
- enum Type : uint32_t {
- NO_INIT,
- INT32,
- UINT32,
- CNTR32,
- INT64,
- UINT64,
- CNTR64,
- FLOAT,
- /**
- * Fixed-size string (POD)
- */
- STRING = 0x100,
- /**
- * blobs have no sub-elements and can be thought of as byte arrays.
- * However, bytes cannot be individually addressed by clients.
- */
- BLOB,
- /**
- * Structs. Marked with this flag in addition to their coreIndex.
- */
- STRUCT_FLAG = 0x20000,
- };
- /**
- * Type of the field.
- */
- bitfield<Type> type;
-
- /** Extent of the field */
- uint32_t length;
- /*
- * Note: the last member of a param struct can be of arbitrary length (e.g.
- * if it is T[] array, which extends to the last byte of the parameter.)
- * This is marked with extent 0.
- */
-
- /** Name of the field */
- string name;
- /** Named value type */
- struct NamedValue {
- string name;
- PrimitiveValue value;
- };
- /** Named values for the field */
- vec<NamedValue> namedValues;
-};
-
-/**
- * Struct descriptor.
- */
-struct StructDescriptor {
- /** Struct type */
- ParamIndex type;
- /** Field descriptors for each field */
- vec<FieldDescriptor> fields;
-};
-
-/**
- * Information describing the reason a parameter settings may fail, or
- * may be overriden.
- */
-struct SettingResult {
- /** Failure code (of Codec 2.0 SettingResult failure type) */
- enum Failure : uint32_t {
- /** Parameter is read-only and cannot be set. */
- READ_ONLY,
- /** Parameter mismatches input data. */
- MISMATCH,
- /** Parameter does not accept value. */
- BAD_VALUE,
- /** Parameter is not supported. */
- BAD_TYPE,
- /** Parameter is not supported on the specific port. */
- BAD_PORT,
- /** Parameter is not supported on the specific stream. */
- BAD_INDEX,
- /** Parameter is in conflict with an/other setting(s). */
- CONFLICT,
- /**
- * Parameter is out of range due to other settings. (This failure mode
- * can only be used for strict parameters.)
- */
- UNSUPPORTED,
- /**
- * Requested parameter value is in conflict with an/other setting(s)
- * and has been corrected to the closest supported value. This failure
- * mode is given to provide suggestion to the client as to how to enable
- * the requested parameter value. */
- INFO_CONFLICT,
- /**
- * This failure mode is reported when all the above failure modes do not
- * apply.
- */
- OTHER = 0xffffffff,
- };
- /**
- * The failure type. The framework might not recognize `OTHER`.
- */
- Failure failure;
- /**
- * The failure code.
- * * If #failure is `OTHER`, #failureOther can be used to give more
- * information.
- * * For all other values of #failure, #failureOther is not used.
- * The framework may not inspect this value.
- */
- uint32_t failureOther;
-
- /**
- * Failing (or corrected) field. Currently supported values for the field.
- * This is set if different from the globally supported values (e.g. due to
- * restrictions by another param or input data)
- */
- ParamFieldValues field;
-
- /**
- * Conflicting parameters or fields with
- * (optional) suggested values for any conflicting fields to avoid the conflict.
- */
- vec<ParamFieldValues> conflicts;
-};
-
-/**
- * Data structure for ordering Work objects. Each member is used for comparing
- * urgency in the same fashion: a smaller value indicates that the associated
- * Work object is more urgent.
- */
-struct WorkOrdinal {
- /**
- * Timestamp in microseconds - can wrap around.
- */
- uint64_t timestampUs;
- /**
- * Frame index - can wrap around.
- */
- uint64_t frameIndex;
- /**
- * Component specific frame ordinal - can wrap around.
- */
- uint64_t customOrdinal;
-};
-
-/**
- * A structure that holds information of a Block. There are two types of Blocks:
- * NATIVE and POOLED. Each type has its own way of identifying blocks.
- */
-struct BaseBlock {
- enum Type : int32_t {
- NATIVE,
- POOLED,
- };
- /**
- * There are two types of blocks: NATIVE and POOLED.
- */
- Type type;
-
- /**
- * A "NATIVE" block is represented by a native handle.
- */
- handle nativeBlock;
-
- /*
- * A "POOLED" block is represented by `BufferStatusMessage`.
- */
- BufferStatusMessage pooledBlock;
-};
-
-/**
- * A Block in transfer consists of an index into an array of BaseBlock plus some
- * extra information. One BaseBlock may occur in multiple blocks in one
- * `WorkBundle`.
- */
-struct Block {
- /**
- * Identity of the BaseBlock within a WorkBundle. This is an index into the
- * `baseBlocks` array of a `WorkBundle` object.
- */
- uint32_t index;
- /**
- * Metadata associated with the block.
- */
- Params meta;
- /**
- * Fence for synchronizing block access.
- */
- handle fence;
-};
-
-/**
- * Type of buffers processed by a component.
- */
-struct Buffer {
- /**
- * Metadata associated with the buffer.
- */
- Params info;
- /**
- * Blocks contained in the buffer.
- */
- vec<Block> blocks;
-};
-
-/**
- * An extension of Buffer that also contains an index.
- */
-struct InfoBuffer {
- ParamIndex index;
- Buffer buffer;
-};
-
-/**
- * This structure represents a frame with its metadata. A frame consists of an
- * ordered set of buffers, configuration changes, and info buffers along with
- * some non-configuration metadata.
- */
-struct FrameData {
- enum Flags : uint32_t {
- /**
- * For input frames: no output frame will be generated when processing
- * this frame, but metadata must still be processed.
- * For output frames: this frame must be discarded but metadata is still
- * valid.
- */
- DROP_FRAME = (1 << 0),
- /**
- * This frame is the last frame of the current stream. Further frames
- * are part of a new stream.
- */
- END_OF_STREAM = (1 << 1),
- /**
- * This frame must be discarded with its metadata.
- * This flag is only set by components - e.g. as a response to the flush
- * command.
- */
- DISCARD_FRAME = (1 << 2),
- /**
- * This frame contains only codec-specific configuration data, and no
- * actual access unit.
- *
- * \deprecated Pass codec configuration with the codec-specific
- * configuration info together with the access unit.
- */
- CODEC_CONFIG = (1u << 31),
- };
-
- /**
- * Frame flags.
- */
- bitfield<Flags> flags;
-
- /**
- * Ordinal of the frame.
- */
- WorkOrdinal ordinal;
-
- /**
- * Frame buffers.
- */
- vec<Buffer> buffers;
-
- /**
- * Params determining a configuration update.
- */
- Params configUpdate;
-
- /**
- * Info buffers.
- */
- vec<InfoBuffer> infoBuffers;
-};
-
-/**
- * Struct for
- */
-struct Worklet {
- /**
- * List of Params describing tunings.
- */
- vec<Params> tunings;
-
- /**
- * List of failures.
- */
- vec<SettingResult> failures;
-
- /**
- * Output frame data.
- */
- FrameData output;
-
- /* Note: Component id is not necessary as tunneling is not supported. */
-};
-
-/**
- * This structure holds information about a single work item. It must be passed
- * by the client to the component.
- */
-struct Work {
- /**
- * FrameData for the input. Indices of Blocks inside #input refer to
- * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
- */
- FrameData input;
- /**
- * Worklet. Indices of Blocks inside `worklet.output` refer to
- * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
- */
- Worklet worklet;
- /**
- * Whether the worklet was processed or not.
- */
- bool workletProcessed;
- Status result;
-};
-
-/**
- * This structure holds a list of Work objects and a list of BaseBlocks.
- */
-struct WorkBundle {
- /**
- * A list of Work items.
- */
- vec<Work> works;
- /**
- * A list of blocks indexed by elements of #works.
- */
- vec<BaseBlock> baseBlocks;
-};
-
-/**
- * This structure describes a query for supported values of a field. This is
- * used as input to IConfigurable::queryFieldSupportedValues().
- */
-struct FieldSupportedValuesQuery {
- enum Type : uint32_t {
- /** Query all possible values regardless of other settings */
- POSSIBLE,
- /** Query currently possible values given dependent settings */
- CURRENT,
- };
-
- ParamField field;
- Type type;
-};
-
-/**
- * This structure is used to hold the result from
- * IConfigurable::queryFieldSupportedValues().
- */
-struct FieldSupportedValuesQueryResult {
- Status status;
- FieldSupportedValues values;
-};
-
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
deleted file mode 100644
index e90fe42..0000000
--- a/media/libstagefright/codec2/include/C2.h
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2_H_
-#define C2_H_
-
-#include <errno.h>
-
-#include <string>
-
-/** nanoseconds with arbitrary origin. */
-typedef int64_t c2_nsecs_t;
-
-/** \mainpage Codec2
- *
- * Codec2 is a generic frame-based data processing API.
- *
- * The media subsystem accesses components via the \ref API.
- */
-
-/** \ingroup API
- *
- * The Codec2 API defines the operation of data processing components and their interaction with
- * the rest of the system.
- *
- * Coding Conventions
- *
- * Mitigating Binary Compatibility.
- *
- * While full binary compatibility is not a goal of the API (due to our use of STL), we try to
- * mitigate binary breaks by adhering to the following conventions:
- *
- * - at most one vtable with placeholder virtual methods
- * - all optional/placeholder virtual methods returning a c2_status_t, with C2_OMITTED not requiring
- * any update to input/output arguments.
- * - limiting symbol export of inline methods
- * - use of pimpl (or shared-pimpl)
- *
- * Naming
- *
- * - all classes and types prefix with C2
- * - classes for internal use prefix with _C2
- * - enum values in global namespace prefix with C2_ all caps
- * - enum values inside classes have no C2_ prefix as class already has it
- * - supporting two kinds of enum naming: all-caps and kCamelCase
- * \todo revisit kCamelCase for param-type
- *
- * Aspects
- *
- * Aspects define certain common behavior across a group of objects.
- * - classes whose name matches _C2.*Aspect
- * - only protected constructors
- * - no desctructor and copiable
- * - all methods are inline or static (this is opposite of the interface paradigm where all methods
- * are virtual, which would not work due to the at most one vtable rule.)
- * - only private variables (this prevents subclasses interfering with the aspects.)
- */
-
-/// \defgroup types Common Types
-/// @{
-
-/**
- * C2String: basic string implementation
- */
-typedef std::string C2String;
-
-/**
- * C2StringLiteral: basic string literal implementation.
- * \note these are never owned by any object, and can only refer to C string literals.
- */
-typedef const char *C2StringLiteral;
-
-/**
- * c2_status_t: status codes used.
- */
-enum c2_status_t : int32_t {
-/*
- * Use POSIX errno constants.
- */
- C2_OK = 0, ///< operation completed successfully
-
- // bad input
- C2_BAD_VALUE = EINVAL, ///< argument has invalid value (user error)
- C2_BAD_INDEX = ENXIO, ///< argument uses invalid index (user error)
- C2_CANNOT_DO = ENOTSUP, ///< argument/index is valid but not possible
-
- // bad sequencing of events
- C2_DUPLICATE = EEXIST, ///< object already exists
- C2_NOT_FOUND = ENOENT, ///< object not found
- C2_BAD_STATE = EPERM, ///< operation is not permitted in the current state
- C2_BLOCKING = EWOULDBLOCK, ///< operation would block but blocking is not permitted
- C2_CANCELED = EINTR, ///< operation interrupted/canceled
-
- // bad environment
- C2_NO_MEMORY = ENOMEM, ///< not enough memory to complete operation
- C2_REFUSED = EACCES, ///< missing permission to complete operation
-
- C2_TIMED_OUT = ETIMEDOUT, ///< operation did not complete within timeout
-
- // bad versioning
- C2_OMITTED = ENOSYS, ///< operation is not implemented/supported (optional only)
-
- // unknown fatal
- C2_CORRUPTED = EFAULT, ///< some unexpected error prevented the operation
- C2_NO_INIT = ENODEV, ///< status has not been initialized
-};
-
-/**
- * Type that describes the desired blocking behavior for variable blocking calls. Blocking in this
- * API is used in a somewhat modified meaning such that operations that merely update variables
- * protected by mutexes are still considered "non-blocking" (always used in quotes).
- */
-enum c2_blocking_t : int32_t {
- /**
- * The operation SHALL be "non-blocking". This means that it shall not perform any file
- * operations, or call/wait on other processes. It may use a protected region as long as the
- * mutex is never used to protect code that is otherwise "may block".
- */
- C2_DONT_BLOCK = false,
- /**
- * The operation MAY be temporarily blocking.
- */
- C2_MAY_BLOCK = true,
-};
-
-/// @}
-
-/// \defgroup utils Utilities
-/// @{
-
-#define C2_DO_NOT_COPY(type) \
- type& operator=(const type &) = delete; \
- type(const type &) = delete; \
-
-#define C2_DEFAULT_MOVE(type) \
- type& operator=(type &&) = default; \
- type(type &&) = default; \
-
-#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
-#define C2_CONST __attribute__((const))
-#define C2_HIDE __attribute__((visibility("hidden")))
-#define C2_INTERNAL __attribute__((internal_linkage))
-#define C2_PACK __attribute__((packed))
-#define C2_PURE __attribute__((pure))
-
-#define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
- inline bool operator!=(const type &other) const { return !(*this == other); } \
- inline bool operator<=(const type &other) const { return (*this == other) || (*this < other); } \
- inline bool operator>=(const type &other) const { return !(*this < other); } \
- inline bool operator>(const type &other) const { return !(*this < other) && !(*this == other); }
-
-#define DEFINE_FIELD_BASED_COMPARISON_OPERATORS(type, field) \
- inline bool operator<(const type &other) const { return field < other.field; } \
- inline bool operator==(const type &other) const { return field == other.field; } \
- DEFINE_OTHER_COMPARISON_OPERATORS(type)
-
-#define DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(type, field, mask) \
- inline bool operator<(const type &other) const { \
- return (field & mask) < (other.field & (mask)); \
- } \
- inline bool operator==(const type &other) const { \
- return (field & mask) == (other.field & (mask)); \
- } \
- DEFINE_OTHER_COMPARISON_OPERATORS(type)
-
-template<typename T, typename B>
-class C2_HIDE c2_cntr_t;
-
-/// \cond INTERNAL
-
-/// \defgroup utils_internal
-/// @{
-
-template<typename T>
-struct C2_HIDE _c2_cntr_compat_helper {
- template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
- C2_ALLOW_OVERFLOW
- inline static constexpr T get(const U &value) {
- return T(value);
- }
-
- template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
- C2_ALLOW_OVERFLOW
- inline static constexpr T get(const c2_cntr_t<U, void> &value) {
- return T(value.mValue);
- }
-};
-
-/// @}
-
-/// \endcond
-
-/**
- * Integral counter type.
- *
- * This is basically an unsigned integral type that is NEVER checked for overflow/underflow - and
- * comparison operators are redefined.
- *
- * \note Comparison of counter types is not fully transitive, e.g.
- * it could be that a > b > c but a !> c.
- * std::less<>, greater<>, less_equal<> and greater_equal<> specializations yield total ordering,
- * but may not match semantic ordering of the values.
- *
- * Technically: counter types represent integer values: A * 2^N + value, where A can be arbitrary.
- * This makes addition, subtraction, multiplication (as well as bitwise operations) well defined.
- * However, division is in general not well defined, as the result may depend on A. This is also
- * true for logical operators and boolean conversion.
- *
- * Even though well defined, bitwise operators are not implemented for counter types as they are not
- * meaningful.
- */
-template<typename T, typename B=typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type>
-class C2_HIDE c2_cntr_t {
- using compat = _c2_cntr_compat_helper<T>;
-
- T mValue;
- constexpr static T HALF_RANGE = T(~0) ^ (T(~0) >> 1);
-
- template<typename U>
- friend struct _c2_cntr_compat_helper;
-public:
-
- /**
- * Default constructor. Initialized counter to 0.
- */
- inline constexpr c2_cntr_t() : mValue(T(0)) {}
-
- /**
- * Construct from a compatible type.
- */
- template<typename U>
- inline constexpr c2_cntr_t(const U &value) : mValue(compat::get(value)) {}
-
- /**
- * Peek as underlying signed type.
- */
- C2_ALLOW_OVERFLOW
- inline constexpr typename std::make_signed<T>::type peek() const {
- return static_cast<typename std::make_signed<T>::type>(mValue);
- }
-
- /**
- * Peek as underlying unsigned type.
- */
- inline constexpr T peeku() const {
- return mValue;
- }
-
- /**
- * Peek as long long - e.g. for printing.
- */
- C2_ALLOW_OVERFLOW
- inline constexpr long long peekll() const {
- return (long long)mValue;
- }
-
- /**
- * Peek as unsigned long long - e.g. for printing.
- */
- C2_ALLOW_OVERFLOW
- inline constexpr unsigned long long peekull() const {
- return (unsigned long long)mValue;
- }
-
- /**
- * Convert to a smaller counter type. This is always safe.
- */
- template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type>
- inline operator c2_cntr_t<U>() {
- return c2_cntr_t<U>(mValue);
- }
-
- /**
- * Arithmetic operators
- */
-
-#define DEFINE_C2_CNTR_BINARY_OP(attrib, op, op_assign) \
- template<typename U> \
- attrib inline c2_cntr_t<T>& operator op_assign(const U &value) { \
- mValue op_assign compat::get(value); \
- return *this; \
- } \
- \
- template<typename U, typename E=decltype(compat::get(U(0)))> \
- attrib inline constexpr c2_cntr_t<T> operator op(const U &value) const { \
- return c2_cntr_t<T>(mValue op compat::get(value)); \
- } \
- \
- template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> \
- attrib inline constexpr c2_cntr_t<U> operator op(const c2_cntr_t<U> &value) const { \
- return c2_cntr_t<U>(U(mValue) op value.peeku()); \
- }
-
-#define DEFINE_C2_CNTR_UNARY_OP(attrib, op) \
- attrib inline constexpr c2_cntr_t<T> operator op() const { \
- return c2_cntr_t<T>(op mValue); \
- }
-
-#define DEFINE_C2_CNTR_CREMENT_OP(attrib, op) \
- attrib inline c2_cntr_t<T> &operator op() { \
- op mValue; \
- return *this; \
- } \
- attrib inline c2_cntr_t<T> operator op(int) { \
- return c2_cntr_t<T, void>(mValue op); \
- }
-
- DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
- DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
- DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
-
- DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
- DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
-
- DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
- DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
-
- template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
- C2_ALLOW_OVERFLOW
- inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
- return c2_cntr_t<T>(mValue << value);
- }
-
- template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
- C2_ALLOW_OVERFLOW
- inline c2_cntr_t<T> &operator<<=(const U &value) {
- mValue <<= value;
- return *this;
- }
-
- /**
- * Comparison operators
- */
- C2_ALLOW_OVERFLOW
- inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
- return T(other.mValue - mValue) < HALF_RANGE;
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
- return T(mValue - other.mValue) < HALF_RANGE;
- }
-
- inline constexpr bool operator==(const c2_cntr_t<T> &other) const {
- return mValue == other.mValue;
- }
-
- inline constexpr bool operator!=(const c2_cntr_t<T> &other) const {
- return !(*this == other);
- }
-
- inline constexpr bool operator<(const c2_cntr_t<T> &other) const {
- return *this <= other && *this != other;
- }
-
- inline constexpr bool operator>(const c2_cntr_t<T> &other) const {
- return *this >= other && *this != other;
- }
-};
-
-template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
-inline constexpr c2_cntr_t<T> operator+(const U &a, const c2_cntr_t<T> &b) {
- return b + a;
-}
-
-template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
-inline constexpr c2_cntr_t<T> operator-(const U &a, const c2_cntr_t<T> &b) {
- return c2_cntr_t<T>(a) - b;
-}
-
-template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
-inline constexpr c2_cntr_t<T> operator*(const U &a, const c2_cntr_t<T> &b) {
- return b * a;
-}
-
-typedef c2_cntr_t<uint32_t> c2_cntr32_t; /** 32-bit counter type */
-typedef c2_cntr_t<uint64_t> c2_cntr64_t; /** 64-bit counter type */
-
-/// \cond INTERNAL
-
-/// \defgroup utils_internal
-/// @{
-
-template<typename... T> struct c2_types;
-
-/** specialization for a single type */
-template<typename T>
-struct c2_types<T> {
- typedef typename std::decay<T>::type wide_type;
- typedef wide_type narrow_type;
- typedef wide_type min_type; // type for min(T...)
-};
-
-/** specialization for two types */
-template<typename T, typename U>
-struct c2_types<T, U> {
- static_assert(std::is_floating_point<T>::value == std::is_floating_point<U>::value,
- "mixing floating point and non-floating point types is disallowed");
- static_assert(std::is_signed<T>::value == std::is_signed<U>::value,
- "mixing signed and unsigned types is disallowed");
-
- typedef typename std::decay<
- decltype(true ? std::declval<T>() : std::declval<U>())>::type wide_type;
- typedef typename std::decay<
- typename std::conditional<sizeof(T) < sizeof(U), T, U>::type>::type narrow_type;
- typedef typename std::conditional<
- std::is_signed<T>::value, wide_type, narrow_type>::type min_type;
-};
-
-/// @}
-
-/// \endcond
-
-/**
- * Type support utility class. Only supports similar classes, such as:
- * - all floating point
- * - all unsigned/all signed
- * - all pointer
- */
-template<typename T, typename U, typename... V>
-struct c2_types<T, U, V...> {
- /** Common type that accommodates all template parameter types. */
- typedef typename c2_types<typename c2_types<T, U>::wide_type, V...>::wide_type wide_type;
- /** Narrowest type of the template parameter types. */
- typedef typename c2_types<typename c2_types<T, U>::narrow_type, V...>::narrow_type narrow_type;
- /** Type that accommodates the minimum value for any input for the template parameter types. */
- typedef typename c2_types<typename c2_types<T, U>::min_type, V...>::min_type min_type;
-};
-
-/**
- * \ingroup utils_internal
- * specialization for two values */
-template<typename T, typename U>
-inline constexpr typename c2_types<T, U>::wide_type c2_max(const T a, const U b) {
- typedef typename c2_types<T, U>::wide_type wide_type;
- return ({ wide_type a_(a), b_(b); a_ > b_ ? a_ : b_; });
-}
-
-/**
- * Finds the maximum value of a list of "similarly typed" values.
- *
- * This is an extension to std::max where the types do not have to be identical, and the smallest
- * resulting type is used that accommodates the argument types.
- *
- * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
- * unsigned.
- *
- * @return the largest of the input arguments.
- */
-template<typename T, typename U, typename... V>
-constexpr typename c2_types<T, U, V...>::wide_type c2_max(const T a, const U b, const V ... c) {
- typedef typename c2_types<T, U, V...>::wide_type wide_type;
- return ({ wide_type a_(a), b_(c2_max(b, c...)); a_ > b_ ? a_ : b_; });
-}
-
-/**
- * \ingroup utils_internal
- * specialization for two values */
-template<typename T, typename U>
-inline constexpr typename c2_types<T, U>::min_type c2_min(const T a, const U b) {
- typedef typename c2_types<T, U>::wide_type wide_type;
- return ({
- wide_type a_(a), b_(b);
- static_cast<typename c2_types<T, U>::min_type>(a_ < b_ ? a_ : b_);
- });
-}
-
-/**
- * Finds the minimum value of a list of "similarly typed" values.
- *
- * This is an extension to std::min where the types do not have to be identical, and the smallest
- * resulting type is used that accommodates the argument types.
- *
- * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
- * unsigned.
- *
- * @return the smallest of the input arguments.
- */
-template<typename T, typename U, typename... V>
-constexpr typename c2_types<T, U, V...>::min_type c2_min(const T a, const U b, const V ... c) {
- typedef typename c2_types<U, V...>::min_type rest_type;
- typedef typename c2_types<T, rest_type>::wide_type wide_type;
- return ({
- wide_type a_(a), b_(c2_min(b, c...));
- static_cast<typename c2_types<T, rest_type>::min_type>(a_ < b_ ? a_ : b_);
- });
-}
-
-/**
- * \ingroup utils_internal
- */
-template<typename T, typename U, typename V>
-inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) {
- typedef typename c2_types<T, U, V>::wide_type wide_type;
- return ({
- wide_type a_(a), b_(b), c_(c);
- static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_);
- });
-}
-
-/// @}
-
-#include <functional>
-template<typename T>
-struct std::less<::c2_cntr_t<T>> {
- constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
- return lh.peeku() < rh.peeku();
- }
-};
-template<typename T>
-struct std::less_equal<::c2_cntr_t<T>> {
- constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
- return lh.peeku() <= rh.peeku();
- }
-};
-template<typename T>
-struct std::greater<::c2_cntr_t<T>> {
- constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
- return lh.peeku() > rh.peeku();
- }
-};
-template<typename T>
-struct std::greater_equal<::c2_cntr_t<T>> {
- constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
- return lh.peeku() >= rh.peeku();
- }
-};
-
-#endif // C2_H_
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
deleted file mode 100644
index 4bdd20f..0000000
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ /dev/null
@@ -1,2281 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2BUFFER_H_
-#define C2BUFFER_H_
-
-#include <C2.h>
-#include <C2BufferBase.h>
-#include <C2Param.h> // for C2Info
-
-#include <memory>
-#include <vector>
-
-#ifdef __ANDROID__
-#include <android-C2Buffer.h>
-#else
-
-typedef void* C2Handle;
-
-#endif
-
-/// \defgroup buffer Buffers
-/// @{
-
-/// \defgroup buffer_sync Synchronization
-/// @{
-
-/**
- * Synchronization is accomplished using event and fence objects.
- *
- * These are cross-process extensions of promise/future infrastructure.
- * Events are analogous to std::promise<void>, whereas fences are to std::shared_future<void>.
- *
- * Fences and events are shareable/copyable.
- *
- * Fences are used in two scenarios, and all copied instances refer to the same event.
- * \todo do events need to be copyable or should they be unique?
- *
- * acquire sync fence object: signaled when it is safe for the component or client to access
- * (the contents of) an object.
- *
- * release sync fence object: \todo
- *
- * Fences can be backed by hardware. Hardware fences are guaranteed to signal NO MATTER WHAT within
- * a short (platform specific) amount of time; this guarantee is usually less than 15 msecs.
- */
-
-/**
- * Fence object used by components and the framework.
- *
- * Implements the waiting for an event, analogous to a 'future'.
- *
- * To be implemented by vendors if using HW fences.
- */
-class C2Fence {
-public:
- /**
- * Waits for a fence to be signaled with a timeout.
- *
- * \todo a mechanism to cancel a wait - for now the only way to do this is to abandon the
- * event, but fences are shared so canceling a wait will cancel all waits.
- *
- * \param timeoutNs the maximum time to wait in nsecs
- *
- * \retval C2_OK the fence has been signaled
- * \retval C2_TIMED_OUT the fence has not been signaled within the timeout
- * \retval C2_BAD_STATE the fence has been abandoned without being signaled (it will never
- * be signaled)
- * \retval C2_REFUSED no permission to wait for the fence (unexpected - system)
- * \retval C2_CORRUPTED some unknown error prevented waiting for the fence (unexpected)
- */
- c2_status_t wait(c2_nsecs_t timeoutNs);
-
- /**
- * Used to check if this fence is valid (if there is a chance for it to be signaled.)
- * A fence becomes invalid if the controling event is destroyed without it signaling the fence.
- *
- * \return whether this fence is valid
- */
- bool valid() const;
-
- /**
- * Used to check if this fence has been signaled (is ready).
- *
- * \return whether this fence has been signaled
- */
- bool ready() const;
-
- /**
- * Returns a file descriptor that can be used to wait for this fence in a select system call.
- * \note The returned file descriptor, if valid, must be closed by the caller.
- *
- * This can be used in e.g. poll() system calls. This file becomes readable (POLLIN) when the
- * fence is signaled, and bad (POLLERR) if the fence is abandoned.
- *
- * \return a file descriptor representing this fence (with ownership), or -1 if the fence
- * has already been signaled (\todo or abandoned).
- *
- * \todo this must be compatible with fences used by gralloc
- */
- int fd() const;
-
- /**
- * Returns whether this fence is a hardware-backed fence.
- * \return whether this is a hardware fence
- */
- bool isHW() const;
-
- /**
- * Null-fence. A fence that has fired.
- */
- constexpr C2Fence() : mImpl(nullptr) { }
-
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
- C2Fence(std::shared_ptr<Impl> impl);
- friend struct _C2FenceFactory;
-};
-
-/**
- * Event object used by components and the framework.
- *
- * Implements the signaling of an event, analogous to a 'promise'.
- *
- * Hardware backed events do not go through this object, and must be exposed directly as fences
- * by vendors.
- */
-class C2Event {
-public:
- /**
- * Returns a fence for this event.
- */
- C2Fence fence() const;
-
- /**
- * Signals (all) associated fence(s).
- * This has no effect no effect if the event was already signaled or abandoned.
- *
- * \retval C2_OK the fence(s) were successfully signaled
- * \retval C2_BAD_STATE the fence(s) have already been abandoned or merged (caller error)
- * \retval C2_DUPLICATE the fence(s) have already been signaled (caller error)
- * \retval C2_REFUSED no permission to signal the fence (unexpected - system)
- * \retval C2_CORRUPTED some unknown error prevented signaling the fence(s) (unexpected)
- */
- c2_status_t fire();
-
- /**
- * Trigger this event from the merging of the supplied fences. This means that it will be
- * abandoned if any of these fences have been abandoned, and it will be fired if all of these
- * fences have been signaled.
- *
- * \retval C2_OK the merging was successfully done
- * \retval C2_NO_MEMORY not enough memory to perform the merging
- * \retval C2_DUPLICATE the fence have already been merged (caller error)
- * \retval C2_BAD_STATE the fence have already been signaled or abandoned (caller error)
- * \retval C2_REFUSED no permission to merge the fence (unexpected - system)
- * \retval C2_CORRUPTED some unknown error prevented merging the fence(s) (unexpected)
- */
- c2_status_t merge(std::vector<C2Fence> fences);
-
- /**
- * Abandons the event and any associated fence(s).
- * \note Call this to explicitly abandon an event before it is destructed to avoid a warning.
- *
- * This has no effect no effect if the event was already signaled or abandoned.
- *
- * \retval C2_OK the fence(s) were successfully signaled
- * \retval C2_BAD_STATE the fence(s) have already been signaled or merged (caller error)
- * \retval C2_DUPLICATE the fence(s) have already been abandoned (caller error)
- * \retval C2_REFUSED no permission to abandon the fence (unexpected - system)
- * \retval C2_CORRUPTED some unknown error prevented signaling the fence(s) (unexpected)
- */
- c2_status_t abandon();
-
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
-};
-
-/// \addtogroup buf_internal Internal
-/// @{
-
-/**
- * Interface for objects that encapsulate an updatable status value.
- */
-struct _C2InnateStatus {
- inline c2_status_t status() const { return mStatus; }
-
-protected:
- _C2InnateStatus(c2_status_t status) : mStatus(status) { }
-
- c2_status_t mStatus; // this status is updatable by the object
-};
-
-/// @}
-
-/**
- * This is a utility template for objects protected by an acquire fence, so that errors during
- * acquiring the object are propagated to the object itself.
- */
-template<typename T>
-class C2Acquirable : public C2Fence {
-public:
- /**
- * Acquires the object protected by an acquire fence. Any errors during the mapping will be
- * passed to the object.
- *
- * \return acquired object potentially invalidated if waiting for the fence failed.
- */
- T get() {
- // TODO:
- // wait();
- return mT;
- }
-
-protected:
- C2Acquirable(c2_status_t error, C2Fence fence, T t) : C2Fence(fence), mInitialError(error), mT(t) { }
-
-private:
- c2_status_t mInitialError;
- T mT; // TODO: move instead of copy
-};
-
-/// @}
-
-/// \defgroup linear Linear Data Blocks
-/// @{
-
-/**************************************************************************************************
- LINEAR ASPECTS, BLOCKS AND VIEWS
-**************************************************************************************************/
-
-/**
- * Basic segment math support.
- */
-struct C2Segment {
- uint32_t offset;
- uint32_t size;
-
- inline constexpr C2Segment(uint32_t offset_, uint32_t size_)
- : offset(offset_),
- size(size_) {
- }
-
- inline constexpr bool isEmpty() const {
- return size == 0;
- }
-
- inline constexpr bool isValid() const {
- return offset <= ~size;
- }
-
- inline constexpr operator bool() const {
- return isValid() && !isEmpty();
- }
-
- inline constexpr bool operator!() const {
- return !bool(*this);
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr bool contains(const C2Segment &other) const {
- if (!isValid() || !other.isValid()) {
- return false;
- } else {
- return offset <= other.offset
- && offset + size >= other.offset + other.size;
- }
- }
-
- inline constexpr bool operator==(const C2Segment &other) const {
- if (!isValid()) {
- return !other.isValid();
- } else {
- return offset == other.offset && size == other.size;
- }
- }
-
- inline constexpr bool operator!=(const C2Segment &other) const {
- return !operator==(other);
- }
-
- inline constexpr bool operator>=(const C2Segment &other) const {
- return contains(other);
- }
-
- inline constexpr bool operator>(const C2Segment &other) const {
- return contains(other) && !operator==(other);
- }
-
- inline constexpr bool operator<=(const C2Segment &other) const {
- return other.contains(*this);
- }
-
- inline constexpr bool operator<(const C2Segment &other) const {
- return other.contains(*this) && !operator==(other);
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr uint32_t end() const {
- return offset + size;
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr C2Segment intersect(const C2Segment &other) const {
- return C2Segment(c2_max(offset, other.offset),
- c2_min(end(), other.end()) - c2_max(offset, other.offset));
- }
-
- /** clamps end to offset if it overflows */
- inline constexpr C2Segment normalize() const {
- return C2Segment(offset, c2_max(offset, end()) - offset);
- }
-
- /** clamps end to max if it overflows */
- inline constexpr C2Segment saturate() const {
- return C2Segment(offset, c2_min(size, ~offset));
- }
-
-};
-
-/**
- * Common aspect for all objects that have a linear capacity.
- */
-class _C2LinearCapacityAspect {
-/// \name Linear capacity interface
-/// @{
-public:
- inline constexpr uint32_t capacity() const { return mCapacity; }
-
- inline constexpr operator C2Segment() const {
- return C2Segment(0, mCapacity);
- }
-
-protected:
-
-#if UINTPTR_MAX == 0xffffffff
- static_assert(sizeof(size_t) == sizeof(uint32_t), "size_t is too big");
-#else
- static_assert(sizeof(size_t) > sizeof(uint32_t), "size_t is too small");
- // explicitly disable construction from size_t
- inline explicit _C2LinearCapacityAspect(size_t capacity) = delete;
-#endif
-
- inline explicit constexpr _C2LinearCapacityAspect(uint32_t capacity)
- : mCapacity(capacity) { }
-
- inline explicit constexpr _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
- : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
-
-private:
- uint32_t mCapacity;
-/// @}
-};
-
-/**
- * Aspect for objects that have a linear range inside a linear capacity.
- *
- * This class is copiable.
- */
-class _C2LinearRangeAspect : public _C2LinearCapacityAspect {
-/// \name Linear range interface
-/// @{
-public:
- inline constexpr uint32_t offset() const { return mOffset; }
- inline constexpr uint32_t endOffset() const { return mOffset + mSize; }
- inline constexpr uint32_t size() const { return mSize; }
-
- inline constexpr operator C2Segment() const {
- return C2Segment(mOffset, mSize);
- }
-
-private:
- // subrange of capacity [0, capacity] & [size, size + offset]
- inline constexpr _C2LinearRangeAspect(uint32_t capacity_, size_t offset, size_t size)
- : _C2LinearCapacityAspect(capacity_),
- mOffset(c2_min(offset, capacity())),
- mSize(c2_min(size, capacity() - mOffset)) {
- }
-
-protected:
- // copy constructor (no error check)
- inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
- : _C2LinearCapacityAspect(other.capacity()),
- mOffset(other.offset()),
- mSize(other.size()) {
- }
-
- // parent capacity range [0, capacity]
- inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
- : _C2LinearCapacityAspect(parent),
- mOffset(0),
- mSize(capacity()) {
- }
-
- // subrange of parent capacity [0, capacity] & [size, size + offset]
- inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
- : _C2LinearCapacityAspect(parent),
- mOffset(c2_min(offset, capacity())),
- mSize(c2_min(size, capacity() - mOffset)) {
- }
-
- // subsection of the parent's and [offset, offset + size] ranges
- inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
- : _C2LinearCapacityAspect(parent),
- mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
- mSize(std::min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) {
- }
-
-public:
- inline constexpr _C2LinearRangeAspect childRange(size_t offset, size_t size) const {
- return _C2LinearRangeAspect(
- mSize,
- c2_min(c2_max(offset, mOffset), capacity()) - mOffset,
- c2_min(c2_min(size, mSize), capacity() - c2_min(c2_max(offset, mOffset), capacity())));
- }
-
- friend class _C2EditableLinearRangeAspect;
- // invariants 0 <= mOffset <= mOffset + mSize <= capacity()
- uint32_t mOffset;
- uint32_t mSize;
-/// @}
-};
-
-/**
- * Utility class for safe range calculations using size_t-s.
- */
-class C2LinearRange : public _C2LinearRangeAspect {
-public:
- inline constexpr C2LinearRange(const _C2LinearCapacityAspect &parent, size_t offset, size_t size)
- : _C2LinearRangeAspect(&parent, offset, size) { }
-
- inline constexpr C2LinearRange(const _C2LinearRangeAspect &parent, size_t offset, size_t size)
- : _C2LinearRangeAspect(&parent, offset, size) { }
-
- inline constexpr C2LinearRange intersect(size_t offset, size_t size) const {
- return C2LinearRange(*this, offset, size);
- }
-};
-
-/**
- * Utility class for simple and safe capacity and range construction.
- */
-class C2LinearCapacity : public _C2LinearCapacityAspect {
-public:
- inline constexpr explicit C2LinearCapacity(size_t capacity)
- : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) { }
-
- inline constexpr C2LinearRange range(size_t offset, size_t size) const {
- return C2LinearRange(*this, offset, size);
- }
-};
-
-/**
- * Aspect for objects that have an editable linear range.
- *
- * This class is copiable.
- */
-class _C2EditableLinearRangeAspect : public _C2LinearRangeAspect {
- using _C2LinearRangeAspect::_C2LinearRangeAspect;
-
-public:
-/// \name Editable linear range interface
-/// @{
-
- /**
- * Sets the offset to |offset|, while trying to keep the end of the buffer unchanged (e.g.
- * size will grow if offset is decreased, and may shrink if offset is increased.) Returns
- * true if successful, which is equivalent to if 0 <= |offset| <= capacity().
- *
- * Note: setting offset and size will yield different result depending on the order of the
- * operations. Always set offset first to ensure proper size.
- */
- inline bool setOffset(uint32_t offset) {
- if (offset > capacity()) {
- return false;
- }
-
- if (offset > mOffset + mSize) {
- mSize = 0;
- } else {
- mSize = mOffset + mSize - offset;
- }
- mOffset = offset;
- return true;
- }
-
- /**
- * Sets the size to |size|. Returns true if successful, which is equivalent to
- * if 0 <= |size| <= capacity() - offset().
- *
- * Note: setting offset and size will yield different result depending on the order of the
- * operations. Always set offset first to ensure proper size.
- */
- inline bool setSize(uint32_t size) {
- if (size > capacity() - mOffset) {
- return false;
- } else {
- mSize = size;
- return true;
- }
- }
-
- /**
- * Sets the offset to |offset| with best effort. Same as setOffset() except that offset will
- * be clamped to the buffer capacity.
- *
- * Note: setting offset and size (even using best effort) will yield different result depending
- * on the order of the operations. Always set offset first to ensure proper size.
- */
- inline void setOffset_be(uint32_t offset) {
- (void)setOffset(c2_min(offset, capacity()));
- }
-
- /**
- * Sets the size to |size| with best effort. Same as setSize() except that the selected region
- * will be clamped to the buffer capacity (e.g. size is clamped to [0, capacity() - offset()]).
- *
- * Note: setting offset and size (even using best effort) will yield different result depending
- * on the order of the operations. Always set offset first to ensure proper size.
- */
- inline void setSize_be(uint32_t size) {
- mSize = c2_min(size, capacity() - mOffset);
- }
-/// @}
-};
-
-/**************************************************************************************************
- ALLOCATIONS
-**************************************************************************************************/
-
-/// \ingroup allocator Allocation and memory placement
-/// @{
-
-class C2LinearAllocation;
-class C2GraphicAllocation;
-
-/**
- * Allocators are used by the framework to allocate memory (allocations) for buffers. They can
- * support either 1D or 2D allocations.
- *
- * \note In theory they could support both, but in practice, we will use only one or the other.
- *
- * Never constructed on stack.
- *
- * Allocators are provided by vendors.
- */
-class C2Allocator {
-public:
- /**
- * Allocator ID type.
- */
- typedef uint32_t id_t;
- enum : id_t {
- BAD_ID = 0xBADD, // invalid allocator ID
- };
-
- /**
- * Allocation types. This is a bitmask and is used in C2Allocator::Info
- * to list the supported allocation types of an allocator.
- */
- enum type_t : uint32_t {
- LINEAR = 1 << 0, //
- GRAPHIC = 1 << 1,
- };
-
- /**
- * Information about an allocator.
- *
- * Allocators don't have a query API so all queriable information is stored here.
- */
- struct Traits {
- C2String name; ///< allocator name
- id_t id; ///< allocator ID
- type_t supportedTypes; ///< supported allocation types
- C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
- C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
- };
-
- /**
- * Returns the unique name of this allocator.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the name of this allocator.
- * \retval an empty string if there was not enough memory to allocate the actual name.
- */
- virtual C2String getName() const = 0;
-
- /**
- * Returns a unique ID for this allocator. This ID is used to get this allocator from the
- * allocator store, and to identify this allocator across all processes.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a unique ID for this allocator.
- */
- virtual id_t getId() const = 0;
-
- /**
- * Returns the allocator traits.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * Allocators don't have a full-fledged query API, only this method.
- *
- * \return allocator information
- */
- virtual std::shared_ptr<const Traits> getTraits() const = 0;
-
- /**
- * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
- * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param capacity the size of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param usage the memory usage info for the requested allocation. \note that the
- * returned allocation may be later used/mapped with different usage.
- * The allocator should layout the buffer to be optimized for this usage,
- * but must support any usage. One exception: protected buffers can
- * only be used in a protected scenario.
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_REFUSED no permission to complete the allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t newLinearAllocation(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle the handle for the existing allocation
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_REFUSED no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t priorLinearAllocation(
- const C2Handle *handle __unused,
- std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
- * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param width the width of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param height the height of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param format the pixel format of requested allocation. This could be a vendor
- * specific format.
- * \param usage the memory usage info for the requested allocation. \note that the
- * returned allocation may be later used/mapped with different usage.
- * The allocator should layout the buffer to be optimized for this usage,
- * but must support any usage. One exception: protected buffers can
- * only be used in a protected scenario.
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_REFUSED no permission to complete the allocation
- * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t newGraphicAllocation(
- uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
- C2MemoryUsage usage __unused,
- std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * (Re)creates a 2D allocation from a native handle. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle the handle for the existing allocation
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_REFUSED no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
- */
- virtual c2_status_t priorGraphicAllocation(
- const C2Handle *handle __unused,
- std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
-protected:
- C2Allocator() = default;
-
- virtual ~C2Allocator() = default;
-};
-
-/**
- * \ingroup linear allocator
- * 1D allocation interface.
- */
-class C2LinearAllocation : public _C2LinearCapacityAspect {
-public:
- /**
- * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
- * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
- * |fence| will contain an acquire sync fence object. If it is already
- * safe to access the buffer contents, then it will contain an empty (already fired) fence.
- *
- * \param offset starting position of the portion to be mapped (this does not have to
- * be page aligned)
- * \param size size of the portion to be mapped (this does not have to be page
- * aligned)
- * \param usage the desired usage. \todo this must be kSoftwareRead and/or
- * kSoftwareWrite.
- * \param fence a pointer to a fence object if an async mapping is requested. If
- * not-null, and acquire fence will be stored here on success, or empty
- * fence on failure. If null, the mapping will be synchronous.
- * \param addr a pointer to where the starting address of the mapped portion will be
- * stored. On failure, nullptr will be stored here.
- *
- * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
- * is no need for this for 1D buffers.
- * \todo Do we need to support sync operation as we could just wait for the fence?
- *
- * \retval C2_OK the operation was successful
- * \retval C2_REFUSED no permission to map the portion
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_DUPLICATE if the allocation is already mapped.
- * \retval C2_NO_MEMORY not enough memory to complete the operation
- * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
- * the usage flags are invalid (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- */
- virtual c2_status_t map(
- size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence /* nullable */,
- void **addr /* nonnull */) = 0;
-
- /**
- * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
- * passed to and returned by |map|; otherwise, this operation is a no-op.
- *
- * \param addr starting address of the mapped region
- * \param size size of the mapped region
- * \param fence a pointer to a fence object if an async unmapping is requested. If
- * not-null, a release fence will be stored here on success, or empty fence
- * on failure. This fence signals when the original allocation contains
- * all changes that happened to the mapped region. If null, the unmapping
- * will be synchronous.
- *
- * \retval C2_OK the operation was successful
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NOT_FOUND if the allocation was not mapped previously.
- * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
- * regions (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- * \retval C2_REFUSED no permission to unmap the portion (unexpected - system)
- */
- virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fence /* nullable */) = 0;
-
- /**
- * Returns the allocator ID for this allocation. This is useful to put the handle into context.
- */
- virtual C2Allocator::id_t getAllocatorId() const = 0;
-
- /**
- * Returns a pointer to the allocation handle.
- */
- virtual const C2Handle *handle() const = 0;
-
- /**
- * Returns true if this is the same allocation as |other|.
- */
- virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
-
-protected:
- // \todo should we limit allocation directly?
- C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
- virtual ~C2LinearAllocation() = default;
-};
-
-class C2CircularBlock;
-class C2LinearBlock;
-class C2GraphicBlock;
-
-/**
- * Block pools are used by components to obtain output buffers in an efficient way. They can
- * support either linear (1D), circular (1D) or graphic (2D) blocks.
- *
- * Block pools decouple the recycling of memory/allocations from the components. They are meant to
- * be an opaque service (there are no public APIs other than obtaining blocks) provided by the
- * platform. Block pools are also meant to decouple allocations from memory used by buffers. This
- * is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
- * their name suggest, block pools maintain a pool of memory blocks. When a component asks for
- * a memory block, pools will try to return a free memory block already in the pool. If no such
- * block exists, they will allocate memory using the backing allocator and allot a block on that
- * allocation. When blocks are no longer used in the system, they are recycled back to the block
- * pool and are available as free blocks.
- *
- * Never constructed on stack.
- */
-class C2BlockPool {
-public:
- /**
- * Block pool ID type.
- */
- typedef uint64_t local_id_t;
-
- enum : local_id_t {
- BASIC_LINEAR = 0, ///< ID of basic (unoptimized) block pool for fetching 1D blocks
- BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
- PLATFORM_START = 0x10,
- };
-
- /**
- * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
- * It is only valid in the current process.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a local ID for this block pool.
- */
- virtual local_id_t getLocalId() const = 0;
-
- /**
- * Returns the ID of the backing allocator of this block pool.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the ID of the backing allocator of this block pool.
- */
- virtual C2Allocator::id_t getAllocatorId() const = 0;
-
- /**
- * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
- * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param capacity the size of requested block.
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr will
- * be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this pool does not support linear blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchLinearBlock(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
- * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param capacity the size of requested circular block. (note: the size of the obtained
- * block could be slightly larger, e.g. to accommodate any system-required
- * alignment)
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this pool does not support circular blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchCircularBlock(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
- * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param width the width of requested block (the obtained block could be slightly larger, e.g.
- * to accommodate any system-required alignment)
- * \param height the height of requested block (the obtained block could be slightly larger,
- * e.g. to accommodate any system-required alignment)
- * \param format the pixel format of requested block. This could be a vendor specific format.
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
- * error)
- * \retval C2_OMITTED this pool does not support 2D blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchGraphicBlock(
- uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
- C2MemoryUsage usage __unused,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
-protected:
- C2BlockPool() = default;
-
- virtual ~C2BlockPool() = default;
-};
-
-/// @}
-
-// ================================================================================================
-// BLOCKS
-// ================================================================================================
-
-/**
- * Blocks are sections of allocations. They can be either 1D or 2D.
- */
-
-class C2LinearAllocation;
-
-/**
- * A 1D block.
- *
- * \note capacity() is not meaningful for users of blocks; instead size() is the capacity of the
- * usable portion. Use and offset() and size() if accessing the block directly through its handle
- * to represent the allotted range of the underlying allocation to this block.
- */
-class C2Block1D : public _C2LinearRangeAspect {
-public:
- /**
- * Returns the underlying handle for this allocation.
- *
- * \note that the block and its block pool has shared ownership of the handle
- * and if all references to the block are released, the underlying block
- * allocation may get reused even if a client keeps a clone of this handle.
- */
- const C2Handle *handle() const;
-
- /**
- * Returns the allocator's ID that created the underlying allocation for this block. This
- * provides the context for understanding the handle.
- */
- C2Allocator::id_t getAllocatorId() const;
-
-protected:
- class Impl;
- /** construct a block. */
- C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
-
- friend struct _C2BlockFactory;
- std::shared_ptr<Impl> mImpl;
-};
-
-/**
- * Read view provides read-only access for a linear memory segment.
- *
- * This class is copiable.
- */
-class C2ReadView : public _C2LinearCapacityAspect {
-public:
- /**
- * \return pointer to the start of the block or nullptr on error.
- * This pointer is only valid during the lifetime of this view or until it is released.
- */
- const uint8_t *data() const;
-
- /**
- * Returns a portion of this view.
- *
- * \param offset the start offset of the portion. \note This is clamped to the capacity of this
- * view.
- * \param size the size of the portion. \note This is clamped to the remaining data from offset.
- *
- * \return a read view containing a portion of this view
- */
- C2ReadView subView(size_t offset, size_t size) const;
-
- /**
- * \return error during the creation/mapping of this view.
- */
- c2_status_t error() const;
-
- /**
- * Releases this view. This sets error to C2_NO_INIT.
- */
- //void release();
-
-protected:
- class Impl;
- C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size);
- explicit C2ReadView(c2_status_t error);
-
-private:
- friend struct _C2BlockFactory;
- std::shared_ptr<Impl> mImpl;
- uint32_t mOffset; /**< offset into the linear block backing this read view */
-};
-
-/**
- * Write view provides read/write access for a linear memory segment.
- *
- * This class is copiable. \todo movable only?
- */
-class C2WriteView : public _C2EditableLinearRangeAspect {
-public:
- /**
- * Start of the block.
- *
- * \return pointer to the start of the block or nullptr on error.
- * This pointer is only valid during the lifetime of this view or until it is released.
- */
- uint8_t *base();
-
- /**
- * \return pointer to the block at the current offset or nullptr on error.
- * This pointer is only valid during the lifetime of this view or until it is released.
- */
- uint8_t *data();
-
- /**
- * \return error during the creation/mapping of this view.
- */
- c2_status_t error() const;
-
- /**
- * Releases this view. This sets error to C2_NO_INIT.
- */
- //void release();
-
-protected:
- class Impl;
- C2WriteView(std::shared_ptr<Impl> impl);
- explicit C2WriteView(c2_status_t error);
-
-private:
- friend struct _C2BlockFactory;
- std::shared_ptr<Impl> mImpl;
-};
-
-/**
- * A constant (read-only) linear block (portion of an allocation) with an acquire fence.
- * Blocks are unmapped when created, and can be mapped into a read view on demand.
- *
- * This class is copiable and contains a reference to the allocation that it is based on.
- */
-class C2ConstLinearBlock : public C2Block1D {
-public:
- /**
- * Maps this block into memory and returns a read view for it.
- *
- * \return a read view for this block.
- */
- C2Acquirable<C2ReadView> map() const;
-
- /**
- * Returns a portion of this block.
- *
- * \param offset the start offset of the portion. \note This is clamped to the capacity of this
- * block.
- * \param size the size of the portion. \note This is clamped to the remaining data from offset.
- *
- * \return a constant linear block containing a portion of this block
- */
- C2ConstLinearBlock subBlock(size_t offset, size_t size) const;
-
- /**
- * Returns the acquire fence for this block.
- *
- * \return a fence that must be waited on before reading the block.
- */
- C2Fence fence() const { return mFence; }
-
-protected:
- C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence mFence);
-
-private:
- friend struct _C2BlockFactory;
- C2Fence mFence;
-};
-
-/**
- * Linear block is a writeable 1D block. Once written, it can be shared in whole or in parts with
- * consumers/readers as read-only const linear block(s).
- */
-class C2LinearBlock : public C2Block1D {
-public:
- /**
- * Maps this block into memory and returns a write view for it.
- *
- * \return a write view for this block.
- */
- C2Acquirable<C2WriteView> map();
-
- /**
- * Creates a read-only const linear block for a portion of this block; optionally protected
- * by an acquire fence. There are two ways to use this:
- *
- * 1) share ready block after writing data into the block. In this case no fence shall be
- * supplied, and the block shall not be modified after calling this method.
- * 2) share block metadata before actually (finishing) writing the data into the block. In
- * this case a fence must be supplied that will be triggered when the data is written.
- * The block shall be modified only until firing the event for the fence.
- */
- C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
-
-protected:
- C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
-
- friend struct _C2BlockFactory;
-};
-
-/// @}
-
-/**************************************************************************************************
- CIRCULAR BLOCKS AND VIEWS
-**************************************************************************************************/
-
-/// \defgroup circular Circular buffer support
-/// @{
-
-/**
- * Circular blocks can be used to share data between a writer and a reader (and/or other consumers)-
- * in a memory-efficient way by reusing a section of memory. Circular blocks are a bit more complex
- * than single reader/single writer schemes to facilitate block-based consuming of data.
- *
- * They can operate in two modes:
- *
- * 1) one writer that creates blocks to be consumed (this model can be used by components)
- *
- * 2) one writer that writes continuously, and one reader that can creates blocks to be consumed
- * by further recipients (this model is used by the framework, and cannot be used by components.)
- *
- * Circular blocks have four segments with running pointers:
- * - reserved: data reserved and available for the writer
- * - committed: data committed by the writer and available to the reader (if present)
- * - used: data used by consumers (if present)
- * - available: unused data available to be reserved
- */
-class C2CircularBlock : public C2Block1D {
- // TODO: add methods
-
-private:
- size_t mReserved __unused; // end of reserved section
- size_t mCommitted __unused; // end of committed section
- size_t mUsed __unused; // end of used section
- size_t mFree __unused; // end of free section
-};
-
-class _C2CircularBlockSegment : public _C2LinearCapacityAspect {
-public:
- /**
- * Returns the available size for this segment.
- *
- * \return currently available size for this segment
- */
- size_t available() const;
-
- /**
- * Reserve some space for this segment from its current start.
- *
- * \param size desired space in bytes
- * \param fence a pointer to an acquire fence. If non-null, the reservation is asynchronous and
- * a fence will be stored here that will be signaled when the reservation is
- * complete. If null, the reservation is synchronous.
- *
- * \retval C2_OK the space was successfully reserved
- * \retval C2_NO_MEMORY the space requested cannot be reserved
- * \retval C2_TIMED_OUT the reservation timed out \todo when?
- * \retval C2_CORRUPTED some unknown error prevented reserving space. (unexpected)
- */
- c2_status_t reserve(size_t size, C2Fence *fence /* nullable */);
-
- /**
- * Abandons a portion of this segment. This will move to the beginning of this segment.
- *
- * \note This methods is only allowed if this segment is producing blocks.
- *
- * \param size number of bytes to abandon
- *
- * \retval C2_OK the data was successfully abandoned
- * \retval C2_TIMED_OUT the operation timed out (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented abandoning the data (unexpected)
- */
- c2_status_t abandon(size_t size);
-
- /**
- * Share a portion as block(s) with consumers (these are moved to the used section).
- *
- * \note This methods is only allowed if this segment is producing blocks.
- * \note Share does not move the beginning of the segment. (\todo add abandon/offset?)
- *
- * \param size number of bytes to share
- * \param fence fence to be used for the section
- * \param blocks vector where the blocks of the section are appended to
- *
- * \retval C2_OK the portion was successfully shared
- * \retval C2_NO_MEMORY not enough memory to share the portion
- * \retval C2_TIMED_OUT the operation timed out (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented sharing the data (unexpected)
- */
- c2_status_t share(size_t size, C2Fence fence, std::vector<C2ConstLinearBlock> &blocks);
-
- /**
- * Returns the beginning offset of this segment from the start of this circular block.
- *
- * @return beginning offset
- */
- size_t begin();
-
- /**
- * Returns the end offset of this segment from the start of this circular block.
- *
- * @return end offset
- */
- size_t end();
-};
-
-/**
- * A circular write-view is a dynamic mapped view for a segment of a circular block. Care must be
- * taken when using this view so that only the section owned by the segment is modified.
- */
-class C2CircularWriteView : public _C2LinearCapacityAspect {
-public:
- /**
- * Start of the circular block.
- * \note the segment does not own this pointer.
- *
- * \return pointer to the start of the circular block or nullptr on error.
- */
- uint8_t *base();
-
- /**
- * \return error during the creation/mapping of this view.
- */
- c2_status_t error() const;
-};
-
-/**
- * The writer of a circular buffer.
- *
- * Can commit data to a reader (not supported for components) OR share data blocks directly with a
- * consumer.
- *
- * If a component supports outputting data into circular buffers, it must allocate a circular
- * block and use a circular writer.
- */
-class C2CircularWriter : public _C2CircularBlockSegment {
-public:
- /**
- * Commits a portion of this segment to the next segment. This moves the beginning of the
- * segment.
- *
- * \param size number of bytes to commit to the next segment
- * \param fence fence used for the commit (the fence must signal before the data is committed)
- */
- c2_status_t commit(size_t size, C2Fence fence);
-
- /**
- * Maps this block into memory and returns a write view for it.
- *
- * \return a write view for this block.
- */
- C2Acquirable<C2CircularWriteView> map();
-};
-
-/// @}
-
-/// \defgroup graphic Graphic Data Blocks
-/// @{
-
-/**
- * C2Rect: rectangle type with non-negative coordinates.
- *
- * \note This struct has public fields without getters/setters. All methods are inline.
- */
-struct C2Rect {
-// public:
- uint32_t left;
- uint32_t top;
- uint32_t width;
- uint32_t height;
-
- constexpr inline C2Rect()
- : C2Rect(0, 0, 0, 0) { }
-
- constexpr inline C2Rect(uint32_t width_, uint32_t height_)
- : C2Rect(width_, height_, 0, 0) { }
-
- constexpr inline C2Rect(uint32_t width_, uint32_t height_, uint32_t left_, uint32_t top_)
- : left(left_), top(top_), width(width_), height(height_) { }
-
- // utility methods
-
- inline constexpr bool isEmpty() const {
- return width == 0 || height == 0;
- }
-
- inline constexpr bool isValid() const {
- return left <= ~width && top <= ~height;
- }
-
- inline constexpr operator bool() const {
- return isValid() && !isEmpty();
- }
-
- inline constexpr bool operator!() const {
- return !bool(*this);
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr bool contains(const C2Rect &other) const {
- if (!isValid() || !other.isValid()) {
- return false;
- } else {
- return left <= other.left && top <= other.top
- && left + width >= other.left + other.width
- && top + height >= other.top + other.height;
- }
- }
-
- inline constexpr bool operator==(const C2Rect &other) const {
- if (!isValid()) {
- return !other.isValid();
- } else {
- return left == other.left && top == other.top
- && width == other.width && height == other.height;
- }
- }
-
- inline constexpr bool operator!=(const C2Rect &other) const {
- return !operator==(other);
- }
-
- inline constexpr bool operator>=(const C2Rect &other) const {
- return contains(other);
- }
-
- inline constexpr bool operator>(const C2Rect &other) const {
- return contains(other) && !operator==(other);
- }
-
- inline constexpr bool operator<=(const C2Rect &other) const {
- return other.contains(*this);
- }
-
- inline constexpr bool operator<(const C2Rect &other) const {
- return other.contains(*this) && !operator==(other);
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr uint32_t right() const {
- return left + width;
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr uint32_t bottom() const {
- return top + height;
- }
-
- C2_ALLOW_OVERFLOW
- inline constexpr C2Rect intersect(const C2Rect &other) const {
- return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
- c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
- c2_max(left, other.left),
- c2_max(top, other.top));
- }
-
- /** clamps right and bottom to top, left if they overflow */
- inline constexpr C2Rect normalize() const {
- return C2Rect(c2_max(left, right()) - left, c2_max(top, bottom()) - top, left, top);
- }
-};
-
-/**
- * Interface for objects that have a width and height (planar capacity).
- */
-class _C2PlanarCapacityAspect {
-/// \name Planar capacity interface
-/// @{
-public:
- inline constexpr uint32_t width() const { return _mWidth; }
- inline constexpr uint32_t height() const { return _mHeight; }
-
- inline constexpr operator C2Rect() const {
- return C2Rect(_mWidth, _mHeight);
- }
-
-protected:
- inline constexpr _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
- : _mWidth(width), _mHeight(height) { }
-
- inline explicit constexpr _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
- : _mWidth(parent == nullptr ? 0 : parent->width()),
- _mHeight(parent == nullptr ? 0 : parent->height()) { }
-
-private:
- uint32_t _mWidth;
- uint32_t _mHeight;
-/// @}
-};
-
-/**
- * C2PlaneInfo: information on the layout of a singe flexible plane.
- *
- * Public fields without getters/setters.
- */
-struct C2PlaneInfo {
-//public:
- enum channel_t : uint32_t {
- CHANNEL_Y, ///< luma
- CHANNEL_R, ///< red
- CHANNEL_G, ///< green
- CHANNEL_B, ///< blue
- CHANNEL_A, ///< alpha
- CHANNEL_CR, ///< Cr
- CHANNEL_CB, ///< Cb
- } channel;
-
- int32_t colInc; ///< column increment in bytes. may be negative
- int32_t rowInc; ///< row increment in bytes. may be negative
-
- uint32_t colSampling; ///< subsampling compared to width (must be a power of 2)
- uint32_t rowSampling; ///< subsampling compared to height (must be a power of 2)
-
- uint32_t allocatedDepth; ///< size of each sample (must be a multiple of 8)
- uint32_t bitDepth; ///< significant bits per sample
- /**
- * the right shift of the significant bits in the sample. E.g. if a 10-bit significant
- * value is laid out in a 16-bit allocation aligned to LSB (values 0-1023), rightShift
- * would be 0 as the 16-bit value read from the sample does not need to be right shifted
- * and can be used as is (after applying a 10-bit mask of 0x3FF).
- *
- * +--------+--------+
- * | VV|VVVVVVVV|
- * +--------+--------+
- * 15 8 7 0
- *
- * If the value is laid out aligned to MSB, rightShift would be 6, as the value read
- * from the allocated sample must be right-shifted by 6 to get the actual sample value.
- *
- * +--------+--------+
- * |VVVVVVVV|VV |
- * +--------+--------+
- * 15 8 7 0
- */
- uint32_t rightShift;
-
- enum endianness_t : uint32_t {
- NATIVE,
- LITTLE_END, // LITTLE_ENDIAN is reserved macro
- BIG_END, // BIG_ENDIAN is a reserved macro
- } endianness; ///< endianness of the samples
-
- /**
- * The following two fields define the relation between multiple planes. If multiple planes are
- * interleaved, they share a root plane (whichever plane's start address is the lowest), and
- * |offset| is the offset of this plane inside the root plane (in bytes). |rootIx| is the index
- * of the root plane. If a plane is independent, rootIx is its index and offset is 0.
- */
- uint32_t rootIx; ///< index of the root plane
- uint32_t offset; ///< offset of this plane inside of the root plane
-
- inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
- ssize_t offs = 0;
- if (width > 0 && colInc < 0) {
- offs += colInc * (ssize_t)(width - 1);
- }
- if (height > 0 && rowInc < 0) {
- offs += rowInc * (ssize_t)(height - 1);
- }
- return offs;
- }
-
- inline constexpr ssize_t maxOffset(uint32_t width, uint32_t height) const {
- ssize_t offs = (allocatedDepth + 7) >> 3;
- if (width > 0 && colInc > 0) {
- offs += colInc * (ssize_t)(width - 1);
- }
- if (height > 0 && rowInc > 0) {
- offs += rowInc * (ssize_t)(height - 1);
- }
- return offs;
- }
-} C2_PACK;
-
-struct C2PlanarLayout {
-//public:
- enum type_t : uint32_t {
- TYPE_UNKNOWN = 0,
- TYPE_YUV = 0x100, ///< YUV image with 3 planes
- TYPE_YUVA, ///< YUVA image with 4 planes
- TYPE_RGB, ///< RGB image with 3 planes
- TYPE_RGBA, ///< RBGA image with 4 planes
- };
-
- type_t type; // image type
- uint32_t numPlanes; // number of component planes
- uint32_t rootPlanes; // number of layout planes (root planes)
-
- enum plane_index_t : uint32_t {
- PLANE_Y = 0,
- PLANE_U = 1,
- PLANE_V = 2,
- PLANE_R = 0,
- PLANE_G = 1,
- PLANE_B = 2,
- PLANE_A = 3,
- MAX_NUM_PLANES = 4,
- };
-
- C2PlaneInfo planes[MAX_NUM_PLANES];
-};
-
-/**
- * Aspect for objects that have a planar section (crop rectangle).
- *
- * This class is copiable.
- */
-class _C2PlanarSectionAspect : public _C2PlanarCapacityAspect {
-/// \name Planar section interface
-/// @{
-private:
- inline constexpr _C2PlanarSectionAspect(uint32_t width, uint32_t height, const C2Rect &crop)
- : _C2PlanarCapacityAspect(width, height),
- mCrop(std::min(width - std::min(crop.left, width), crop.width),
- std::min(height - std::min(crop.top, height), crop.height),
- std::min(crop.left, width),
- std::min(crop.height, height)) {
- }
-
-public:
- // crop can be an empty rect, does not have to line up with subsampling
- // NOTE: we do not support floating-point crop
- inline constexpr C2Rect crop() const { return mCrop; }
-
- /**
- * Returns a child planar section for |crop|, where the capacity represents this section.
- */
- inline constexpr _C2PlanarSectionAspect childSection(const C2Rect &crop) const {
- return _C2PlanarSectionAspect(
- mCrop.width, mCrop.height,
- // crop and translate |crop| rect
- C2Rect(c2_min(mCrop.right() - c2_clamp(mCrop.left, crop.left, mCrop.right()), crop.width),
- c2_min(mCrop.bottom() - c2_clamp(mCrop.top, crop.top, mCrop.bottom()), crop.height),
- c2_clamp(mCrop.left, crop.left, mCrop.right()) - mCrop.left,
- c2_clamp(mCrop.top, crop.top, mCrop.bottom()) - mCrop.top));
- }
-
-protected:
- inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent)
- : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
-
- inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent, const C2Rect &crop)
- : _C2PlanarCapacityAspect(parent),
- mCrop(parent == nullptr ? C2Rect(0, 0) : ((C2Rect)*parent).intersect(crop).normalize()) { }
-
- inline constexpr _C2PlanarSectionAspect(const _C2PlanarSectionAspect *parent, const C2Rect &crop)
- : _C2PlanarCapacityAspect(parent),
- mCrop(parent == nullptr ? C2Rect(0, 0) : parent->crop().intersect(crop).normalize()) { }
-
-private:
- friend class _C2EditablePlanarSectionAspect;
- C2Rect mCrop;
-/// @}
-};
-
-/**
- * Aspect for objects that have an editable planar section (crop rectangle).
- *
- * This class is copiable.
- */
-class _C2EditablePlanarSectionAspect : public _C2PlanarSectionAspect {
-/// \name Planar section interface
-/// @{
- using _C2PlanarSectionAspect::_C2PlanarSectionAspect;
-
-public:
- // crop can be an empty rect, does not have to line up with subsampling
- // NOTE: we do not support floating-point crop
- inline constexpr C2Rect crop() const { return mCrop; }
-
- /**
- * Sets crop to crop intersected with [(0,0) .. (width, height)]
- */
- inline void setCrop_be(const C2Rect &crop) {
- mCrop.left = std::min(width(), crop.left);
- mCrop.top = std::min(height(), crop.top);
- // It's guaranteed that mCrop.left <= width() && mCrop.top <= height()
- mCrop.width = std::min(width() - mCrop.left, crop.width);
- mCrop.height = std::min(height() - mCrop.top, crop.height);
- }
-
- /**
- * If crop is within the dimensions of this object, it sets crop to it.
- *
- * \return true iff crop is within the dimensions of this object
- */
- inline bool setCrop(const C2Rect &crop) {
- if (width() < crop.width || height() < crop.height
- || width() - crop.width < crop.left || height() - crop.height < crop.top) {
- return false;
- }
- mCrop = crop;
- return true;
- }
-/// @}
-};
-
-/**
- * Utility class for safe range calculations using size_t-s.
- */
-class C2PlanarSection : public _C2PlanarSectionAspect {
-public:
- inline constexpr C2PlanarSection(const _C2PlanarCapacityAspect &parent, const C2Rect &crop)
- : _C2PlanarSectionAspect(&parent, crop) { }
-
- inline constexpr C2PlanarSection(const _C2PlanarSectionAspect &parent, const C2Rect &crop)
- : _C2PlanarSectionAspect(&parent, crop) { }
-
- inline constexpr C2PlanarSection intersect(const C2Rect &crop) const {
- return C2PlanarSection(*this, crop);
- }
-};
-
-/**
- * Utility class for simple and safe planar capacity and section construction.
- */
-class C2PlanarCapacity : public _C2PlanarCapacityAspect {
-public:
- inline constexpr explicit C2PlanarCapacity(size_t width, size_t height)
- : _C2PlanarCapacityAspect(c2_min(width, std::numeric_limits<uint32_t>::max()),
- c2_min(height, std::numeric_limits<uint32_t>::max())) { }
-
- inline constexpr C2PlanarSection section(const C2Rect &crop) const {
- return C2PlanarSection(*this, crop);
- }
-};
-
-
-/**
- * \ingroup graphic allocator
- * 2D allocation interface.
- */
-class C2GraphicAllocation : public _C2PlanarCapacityAspect {
-public:
- /**
- * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
- * memory for flexible access. On success, it fills out |layout| with the plane specifications
- * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
- * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fence| will contain
- * an acquire sync fence object. If it is already safe to access the
- * buffer contents, then it will be an empty (already fired) fence.
- *
- * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffset()/
- * maxOffset().
- *
- * \param rect section to be mapped (this does not have to be aligned)
- * \param usage the desired usage. \todo this must be kSoftwareRead and/or
- * kSoftwareWrite.
- * \param fence a pointer to a fence object if an async mapping is requested. If
- * not-null, and acquire fence will be stored here on success, or empty
- * fence on failure. If null, the mapping will be synchronous.
- * \param layout a pointer to where the mapped planes' descriptors will be
- * stored. On failure, nullptr will be stored here.
- * \param addr pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
- * elements. Only layout.numPlanes elements will be modified on success.
- *
- * \retval C2_OK the operation was successful
- * \retval C2_REFUSED no permission to map the section
- * \retval C2_DUPLICATE there is already a mapped region and this allocation cannot support
- * multi-mapping (caller error)
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NO_MEMORY not enough memory to complete the operation
- * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
- * usage flags are invalid (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-
- */
- virtual c2_status_t map(
- C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
- C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
-
- /**
- * Unmaps a section of an allocation at |addr| with |rect|. These must be parameters previously
- * passed to and returned by |map|; otherwise, this operation is a no-op.
- *
- * \param addr pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
- * elements containing the starting addresses of the mapped layers
- * \param rect boundaries of the mapped section
- * \param fence a pointer to a fence object if an async unmapping is requested. If
- * not-null, a release fence will be stored here on success, or empty fence
- * on failure. This fence signals when the original allocation contains
- * all changes that happened to the mapped section. If null, the unmapping
- * will be synchronous.
- *
- * \retval C2_OK the operation was successful
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NOT_FOUND there is no such mapped region (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- * \retval C2_REFUSED no permission to unmap the section (unexpected - system)
- */
- virtual c2_status_t unmap(
- uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) = 0;
-
- /**
- * Returns the allocator ID for this allocation. This is useful to put the handle into context.
- */
- virtual C2Allocator::id_t getAllocatorId() const = 0;
-
- /**
- * Returns a pointer to the allocation handle.
- */
- virtual const C2Handle *handle() const = 0;
-
- /**
- * Returns true if this is the same allocation as |other|.
- */
- virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
-
-protected:
- using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
- virtual ~C2GraphicAllocation() = default;
-};
-
-class C2GraphicAllocation;
-
-/**
- * A 2D block.
- *
- * \note width()/height() is not meaningful for users of blocks; instead, crop().width() and
- * crop().height() is the capacity of the usable portion. Use and crop() if accessing the block
- * directly through its handle to represent the allotted region of the underlying allocation to this
- * block.
- */
-class C2Block2D : public _C2PlanarSectionAspect {
-public:
- /**
- * Returns the underlying handle for this allocation.
- *
- * \note that the block and its block pool has shared ownership of the handle
- * and if all references to the block are released, the underlying block
- * allocation may get reused even if a client keeps a clone of this handle.
- */
- const C2Handle *handle() const;
-
- /**
- * Returns the allocator's ID that created the underlying allocation for this block. This
- * provides the context for understanding the handle.
- */
- C2Allocator::id_t getAllocatorId() const;
-
-protected:
- class Impl;
- C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
-
- friend struct _C2BlockFactory;
- std::shared_ptr<Impl> mImpl;
-};
-
-/**
- * Graphic view provides read or read-write access for a graphic block.
- *
- * This class is copiable.
- *
- * \note Due to the subsampling of graphic buffers, a read view must still contain a crop rectangle
- * to ensure subsampling is followed. This results in nearly identical interface between read and
- * write views, so C2GraphicView can encompass both of them.
- */
-class C2GraphicView : public _C2EditablePlanarSectionAspect {
-public:
- /**
- * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
- * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
- * plane. Access outside of the crop rect results in an undefined behavior.
- */
- const uint8_t *const *data() const;
-
- /**
- * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
- * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
- * plane. Access outside of the crop rect results in an undefined behavior.
- */
- uint8_t *const *data();
-
- /**
- * \return layout of the graphic block to interpret the returned data.
- */
- const C2PlanarLayout layout() const;
-
- /**
- * Returns a section of this view.
- *
- * \param rect the dimension of the section. \note This is clamped to the crop of this view.
- *
- * \return a read view containing the requested section of this view
- */
- const C2GraphicView subView(const C2Rect &rect) const;
- C2GraphicView subView(const C2Rect &rect);
-
- /**
- * \return error during the creation/mapping of this view.
- */
- c2_status_t error() const;
-
-protected:
- class Impl;
- C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
- explicit C2GraphicView(c2_status_t error);
-
-private:
- friend struct _C2BlockFactory;
- std::shared_ptr<Impl> mImpl;
-};
-
-/**
- * A constant (read-only) graphic block (portion of an allocation) with an acquire fence.
- * Blocks are unmapped when created, and can be mapped into a read view on demand.
- *
- * This class is copiable and contains a reference to the allocation that it is based on.
- */
-class C2ConstGraphicBlock : public C2Block2D {
-public:
- /**
- * Maps this block into memory and returns a read view for it.
- *
- * \return a read view for this block.
- */
- C2Acquirable<const C2GraphicView> map() const;
-
- /**
- * Returns a section of this block.
- *
- * \param rect the coordinates of the section. \note This is clamped to the crop rectangle of
- * this block.
- *
- * \return a constant graphic block containing a portion of this block
- */
- C2ConstGraphicBlock subBlock(const C2Rect &rect) const;
-
- /**
- * Returns the acquire fence for this block.
- *
- * \return a fence that must be waited on before reading the block.
- */
- C2Fence fence() const { return mFence; }
-
-protected:
- C2ConstGraphicBlock(
- std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence);
-
-private:
- friend struct _C2BlockFactory;
- C2Fence mFence;
-};
-
-/**
- * Graphic block is a writeable 2D block. Once written, it can be shared in whole or in part with
- * consumers/readers as read-only const graphic block.
- */
-class C2GraphicBlock : public C2Block2D {
-public:
- /**
- * Maps this block into memory and returns a write view for it.
- *
- * \return a write view for this block.
- */
- C2Acquirable<C2GraphicView> map();
-
- /**
- * Creates a read-only const linear block for a portion of this block; optionally protected
- * by an acquire fence. There are two ways to use this:
- *
- * 1) share ready block after writing data into the block. In this case no fence shall be
- * supplied, and the block shall not be modified after calling this method.
- * 2) share block metadata before actually (finishing) writing the data into the block. In
- * this case a fence must be supplied that will be triggered when the data is written.
- * The block shall be modified only until firing the event for the fence.
- */
- C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);
-
-protected:
- C2GraphicBlock(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
-
- friend struct _C2BlockFactory;
-};
-
-/// @}
-
-/// \defgroup buffer_onj Buffer objects
-/// @{
-
-// ================================================================================================
-// BUFFERS
-// ================================================================================================
-
-/// \todo: Do we still need this?
-///
-// There are 2 kinds of buffers: linear or graphic. Linear buffers can contain a single block, or
-// a list of blocks (LINEAR_CHUNKS). Support for list of blocks is optional, and can allow consuming
-// data from circular buffers or scattered data sources without extra memcpy. Currently, list of
-// graphic blocks is not supported.
-
-class C2LinearBuffer; // read-write buffer
-class C2GraphicBuffer; // read-write buffer
-class C2LinearChunksBuffer;
-
-/**
- * C2BufferData: the main, non-meta data of a buffer. A buffer can contain either linear blocks
- * or graphic blocks, and can contain either a single block or multiple blocks. This is determined
- * by its type.
- */
-class C2BufferData {
-public:
- /**
- * The type of buffer data.
- */
- enum Type : uint32_t {
- LINEAR, ///< the buffer contains a single linear block
- LINEAR_CHUNKS, ///< the buffer contains one or more linear blocks
- GRAPHIC, ///< the buffer contains a single graphic block
- GRAPHIC_CHUNKS, ///< the buffer contains one of more graphic blocks
- };
-
- /**
- * Gets the type of this buffer (data).
- * \return the type of this buffer data.
- */
- Type type() const;
-
- /**
- * Gets the linear blocks of this buffer.
- * \return a constant list of const linear blocks of this buffer.
- * \retval empty list if this buffer does not contain linear block(s).
- */
- const std::vector<C2ConstLinearBlock> linearBlocks() const;
-
- /**
- * Gets the graphic blocks of this buffer.
- * \return a constant list of const graphic blocks of this buffer.
- * \retval empty list if this buffer does not contain graphic block(s).
- */
- const std::vector<C2ConstGraphicBlock> graphicBlocks() const;
-
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
-
-protected:
- // no public constructor
- explicit C2BufferData(const std::vector<C2ConstLinearBlock> &blocks);
- explicit C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks);
-};
-
-/**
- * C2Buffer: buffer base class. These are always used as shared_ptrs. Though the underlying buffer
- * objects (native buffers, ion buffers, or dmabufs) are reference-counted by the system,
- * C2Buffers hold only a single reference.
- *
- * These objects cannot be used on the stack.
- */
-class C2Buffer {
-public:
- /**
- * Gets the buffer's data.
- *
- * \return the buffer's data.
- */
- const C2BufferData data() const;
-
- /**
- * These will still work if used in onDeathNotify.
- */
-#if 0
- inline std::shared_ptr<C2LinearBuffer> asLinearBuffer() const {
- return mType == LINEAR ? std::shared_ptr::reinterpret_cast<C2LinearBuffer>(this) : nullptr;
- }
-
- inline std::shared_ptr<C2GraphicBuffer> asGraphicBuffer() const {
- return mType == GRAPHIC ? std::shared_ptr::reinterpret_cast<C2GraphicBuffer>(this) : nullptr;
- }
-
- inline std::shared_ptr<C2CircularBuffer> asCircularBuffer() const {
- return mType == CIRCULAR ? std::shared_ptr::reinterpret_cast<C2CircularBuffer>(this) : nullptr;
- }
-#endif
-
- ///@name Pre-destroy notification handling
- ///@{
-
- /**
- * Register for notification just prior to the destruction of this object.
- */
- typedef void (*OnDestroyNotify) (const C2Buffer *buf, void *arg);
-
- /**
- * Registers for a pre-destroy notification. This is called just prior to the destruction of
- * this buffer (when this buffer is no longer valid.)
- *
- * \param onDestroyNotify the notification callback
- * \param arg an arbitrary parameter passed to the callback
- *
- * \retval C2_OK the registration was successful.
- * \retval C2_DUPLICATE a notification was already registered for this callback and argument
- * \retval C2_NO_MEMORY not enough memory to register for this callback
- * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
- */
- c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
-
- /**
- * Unregisters a previously registered pre-destroy notification.
- *
- * \param onDestroyNotify the notification callback
- * \param arg an arbitrary parameter passed to the callback
- *
- * \retval C2_OK the unregistration was successful.
- * \retval C2_NOT_FOUND the notification was not found
- * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
- */
- c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
-
- ///@}
-
- virtual ~C2Buffer() = default;
-
- ///@name Buffer-specific arbitrary metadata handling
- ///@{
-
- /**
- * Gets the list of metadata associated with this buffer.
- *
- * \return a constant list of info objects associated with this buffer.
- */
- const std::vector<std::shared_ptr<const C2Info>> info() const;
-
- /**
- * Attaches (or updates) an (existing) metadata for this buffer.
- * If the metadata is stream specific, the stream information will be reset.
- *
- * \param info Metadata to update
- *
- * \retval C2_OK the metadata was successfully attached/updated.
- * \retval C2_NO_MEMORY not enough memory to attach the metadata (this return value is not
- * used if the same kind of metadata is already attached to the buffer).
- */
- c2_status_t setInfo(const std::shared_ptr<C2Info> &info);
-
- /**
- * Checks if there is a certain type of metadata attached to this buffer.
- *
- * \param index the parameter type of the metadata
- *
- * \return true iff there is a metadata with the parameter type attached to this buffer.
- */
- bool hasInfo(C2Param::Type index) const;
-
- /**
- * Removes a metadata from the buffer.
- */
- std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
- ///@}
-
- /**
- * Creates a buffer containing a single linear block.
- *
- * \param block the content of the buffer.
- *
- * \return shared pointer to the created buffer.
- */
- static std::shared_ptr<C2Buffer> CreateLinearBuffer(const C2ConstLinearBlock &block);
-
- /**
- * Creates a buffer containing a single graphic block.
- *
- * \param block the content of the buffer.
- *
- * \return shared pointer to the created buffer.
- */
- static std::shared_ptr<C2Buffer> CreateGraphicBuffer(const C2ConstGraphicBlock &block);
-
-
-
-protected:
- // no public constructor
- explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
- explicit C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks);
-
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
-// Type _mType;
-};
-
-/**
- * An extension of C2Info objects that can contain arbitrary buffer data.
- *
- * \note This object is not describable and contains opaque data.
- */
-class C2InfoBuffer {
-public:
- /**
- * Gets the index of this info object.
- *
- * \return the parameter index.
- */
- const C2Param::Index index() const;
-
- /**
- * Gets the buffer's data.
- *
- * \return the buffer's data.
- */
- const C2BufferData data() const;
-};
-
-/// @}
-
-/// \cond INTERNAL
-
-/// \todo These are no longer used
-
-/// \addtogroup linear
-/// @{
-
-/** \deprecated */
-class C2LinearBuffer
- : public C2Buffer, public _C2LinearRangeAspect,
- public std::enable_shared_from_this<C2LinearBuffer> {
-public:
- /** \todo what is this? */
- const C2Handle *handle() const;
-
-protected:
- inline C2LinearBuffer(const C2ConstLinearBlock &block);
-
-private:
- class Impl;
- Impl *mImpl;
-};
-
-class C2ReadCursor;
-
-class C2WriteCursor {
-public:
- uint32_t remaining() const; // remaining data to be read
- void commit(); // commits the current position. discard data before current position
- void reset() const; // resets position to the last committed position
- // slices off at most |size| bytes, and moves cursor ahead by the number of bytes
- // sliced off.
- C2ReadCursor slice(uint32_t size) const;
- // slices off at most |size| bytes, and moves cursor ahead by the number of bytes
- // sliced off.
- C2WriteCursor reserve(uint32_t size);
- // bool read(T&);
- // bool write(T&);
- C2Fence waitForSpace(uint32_t size);
-};
-
-/// @}
-
-/// \addtogroup graphic
-/// @{
-
-struct C2ColorSpace {
-//public:
- enum Standard {
- BT601,
- BT709,
- BT2020,
- // TODO
- };
-
- enum Range {
- LIMITED,
- FULL,
- // TODO
- };
-
- enum TransferFunction {
- BT709Transfer,
- BT2020Transfer,
- HybridLogGamma2,
- HybridLogGamma4,
- // TODO
- };
-};
-
-/** \deprecated */
-class C2GraphicBuffer : public C2Buffer {
-public:
- // constant attributes
- inline uint32_t width() const { return mWidth; }
- inline uint32_t height() const { return mHeight; }
- inline uint32_t format() const { return mFormat; }
- inline const C2MemoryUsage usage() const { return mUsage; }
-
- // modifiable attributes
-
-
- virtual const C2ColorSpace colorSpace() const = 0;
- // best effort
- virtual void setColorSpace_be(const C2ColorSpace &colorSpace) = 0;
- virtual bool setColorSpace(const C2ColorSpace &colorSpace) = 0;
-
- const C2Handle *handle() const;
-
-protected:
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
- C2MemoryUsage mUsage;
-
- class Impl;
- Impl *mImpl;
-};
-
-/// @}
-
-/// \endcond
-
-/// @}
-
-#endif // C2BUFFER_H_
diff --git a/media/libstagefright/codec2/include/C2BufferBase.h b/media/libstagefright/codec2/include/C2BufferBase.h
deleted file mode 100644
index 68411f2..0000000
--- a/media/libstagefright/codec2/include/C2BufferBase.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2BUFFER_BASE_H_
-#define C2BUFFER_BASE_H_
-
-/// \defgroup allocator Allocation and memory placement
-/// @{
-
-/**
- * Buffer/memory usage bits. These shall be used by the allocators to select optimal memory type/
- * pool and buffer layout. Usage bits are conceptually separated into read and write usage, while
- * the buffer use life-cycle is separated into producers (writers) and consumers (readers).
- * These two concepts are related but not equivalent: consumers may only read buffers and only
- * producers may write to buffers; note, however, that buffer producers may also want or need to
- * read the buffers.
- *
- * Read and write buffer usage bits shall be or-ed to arrive at the full buffer usage. Admittedly,
- * this does not account for the amount of reading and writing (e.g. a buffer may have one or more
- * readers); however, the proper information necessary to properly weigh the various usages would be
- * the amount of data read/written for each usage type. This would result in an integer array of
- * size 64 (or the number of distinct usages) for memory usage, and likely such detailed information
- * would not always be available.
- *
- * That platform-agnostic Codec 2.0 API only defines the bare minimum usages. Platforms shall define
- * usage bits that are appropriate for the platform.
- */
-struct C2MemoryUsage {
-// public:
- /**
- * Buffer read usage.
- */
- enum Read : uint64_t {
- /** Buffer is read by the CPU. */
- CPU_READ = 1 << 0,
- /**
- * Buffer shall only be read by trusted hardware. The definition of trusted hardware is
- * platform specific, but this flag is reserved to prevent mapping this block into CPU
- * readable memory resulting in bus fault. This flag can be used when buffer access must be
- * protected.
- */
- READ_PROTECTED = 1 << 1,
- };
-
- /**
- * Buffer write usage.
- */
- enum Write : uint64_t {
- /** Buffer is writted to by the CPU. */
- CPU_WRITE = 1 << 2,
- /**
- * Buffer shall only be written to by trusted hardware. The definition of trusted hardware
- * is platform specific, but this flag is reserved to prevent mapping this block into CPU
- * writable memory resulting in bus fault. This flag can be used when buffer integrity must
- * be protected.
- */
- WRITE_PROTECTED = 1 << 3,
- };
-
- enum : uint64_t {
- /**
- * Buffer usage bits reserved for the platform. We don't separately reserve read and
- * write usages as platforms may have asymmetric distribution between them.
- */
- PLATFORM_MASK = ~(CPU_READ | CPU_WRITE | READ_PROTECTED | WRITE_PROTECTED),
- };
-
- /** Create a usage from separate consumer and producer usage mask. \deprecated */
- inline C2MemoryUsage(uint64_t consumer, uint64_t producer)
- : expected(consumer | producer) { }
-
- inline explicit C2MemoryUsage(uint64_t expected_)
- : expected(expected_) { }
-
- uint64_t expected; // expected buffer usage
-};
-
-/// @}
-
-#endif // C2BUFFER_BASE_H_
-
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
deleted file mode 100644
index dbcd82d..0000000
--- a/media/libstagefright/codec2/include/C2Component.h
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2COMPONENT_H_
-
-#define C2COMPONENT_H_
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <list>
-#include <memory>
-#include <vector>
-#include <functional>
-
-#include <C2Param.h>
-#include <C2Work.h>
-
-/// \defgroup components Components
-/// @{
-
-struct C2FieldSupportedValuesQuery {
- enum type_t : uint32_t {
- POSSIBLE, ///< query all possible values regardless of other settings
- CURRENT, ///< query currently possible values given dependent settings
- };
-
-private:
- C2ParamField _mField;
- type_t _mType;
-public:
- c2_status_t status;
- C2FieldSupportedValues values;
-
- C2FieldSupportedValuesQuery(const C2ParamField &field_, type_t type_)
- : _mField(field_), _mType(type_), status(C2_NO_INIT) { }
-
- static C2FieldSupportedValuesQuery
- Current(const C2ParamField &field_) {
- return C2FieldSupportedValuesQuery(field_, CURRENT);
- }
-
- static C2FieldSupportedValuesQuery
- Possible(const C2ParamField &field_) {
- return C2FieldSupportedValuesQuery(field_, POSSIBLE);
- }
-
- inline C2ParamField field() const { return _mField; };
-
- inline type_t type() const { return _mType; }
-};
-
-/**
- * Component interface object. This object contains all of the configuration of a potential or
- * actual component. It can be created and used independently of an actual C2Component instance to
- * query support and parameters for various component settings and configurations for a potential
- * component. Actual components also expose this interface.
- */
-
-class C2ComponentInterface {
-public:
- // ALWAYS AVAILABLE METHODS
- // =============================================================================================
-
- /**
- * Returns the name of this component or component interface object.
- * This is a unique name for this component or component interface 'class'; however, multiple
- * instances of this component SHALL have the same name.
- *
- * When attached to a component, this method MUST be supported in any component state.
- * This call does not change the state nor the internal configuration of the component.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the name of this component or component interface object.
- * \retval an empty string if there was not enough memory to allocate the actual name.
- */
- virtual C2String getName() const = 0;
-
- /**
- * Returns a unique ID for this component or interface object.
- * This ID is used as work targets, unique work IDs, and when configuring tunneling.
- *
- * When attached to a component, this method MUST be supported in any component state.
- * This call does not change the state nor the internal configuration of the component.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a unique node ID for this component or component interface instance.
- */
- virtual c2_node_id_t getId() const = 0;
-
- /**
- * Queries a set of parameters from the component or interface object.
- * Querying is performed at best effort: the component SHALL query all supported parameters and
- * skip unsupported ones, heap allocated parameters that could not be allocated or parameters
- * that could not be queried without blocking. Any errors are communicated in the return value.
- * Additionally, preallocated (e.g. stack) parameters that could not be queried are invalidated.
- * Invalid or blocking parameters to be allocated on the heap are omitted from the result.
- *
- * \note Parameter values do not depend on the order of query.
- *
- * \todo This method cannot be used to query info-buffers. Is that a problem?
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- * This call does not change the state nor the internal configuration of the component.
- *
- * This method has a variable blocking behavior based on state.
- * In the stopped state this method MUST be "non-blocking" and return within 1ms.
- * In the running states this method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param[in,out] stackParams a list of params queried. These are initialized specific to each
- * setting; e.g. size and index are set and rest of the members are
- * cleared.
- * \note Flexible settings that are of incorrect size will be
- * invalidated.
- * \param[in] heapParamIndices a vector of param indices for params to be queried and returned
- * on the heap. These parameters will be returned in heapParams.
- * Unsupported param indices will be ignored.
- * \param[in] mayBlock if true (C2_MAY_BLOCK), implementation may momentarily block.
- * Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
- * \param[out] heapParams a list of params where to which the supported heap parameters
- * will be appended in the order they appear in heapParamIndices.
- *
- * \retval C2_OK all parameters could be queried
- * \retval C2_BAD_INDEX all supported parameters could be queried, but some parameters were not
- * supported
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_NO_MEMORY could not allocate memory for a supported parameter
- * \retval C2_BLOCKING the operation must block to complete but mayBlock is false
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_TIMED_OUT could not query the parameters within the time limit (unexpected)
- * (this error code is only allowed for interfaces connected to components
- * in the running state)
- * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
- * (unexpected)
- * (this error code is only allowed for interfaces connected to components)
- */
- virtual c2_status_t query_vb(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
-
- /**
- * Sets a set of parameters for the component or interface object.
- *
- * Tuning is performed at best effort: the component SHALL process the configuration updates in
- * the order they appear in |params|. If any parameter update fails, the component shall
- * communicate the failure in the return value and in |failures|, and still process the
- * remaining parameters. Unsupported parameters are skipped, though they are communicated in
- * ther return value. Most parameters are updated at best effort - such that even if client
- * specifies an unsupported value for a field, the closest supported value is used. On the
- * other hand, strict parameters only accept specific values for their fields, and if the client
- * specifies an unsupported value, the parameter setting shall fail for that field.
- * If the client tries to change the value of a field that requires momentary blocking without
- * setting |mayBlock| to C2_MAY_BLOCK, that parameter shall also be skipped and a specific
- * return value shall be used. Final values for all parameters set are propagated back to the
- * caller in |params|.
- *
- * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
- * update may allow some subsequent values for further parameter updates.
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- *
- * This method has a variable blocking behavior based on state.
- * In the stopped state this method MUST be "non-blocking" and return within 1ms.
- * In the running states this method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param[in,out] params a list of parameter updates. These will be updated to the actual
- * parameter values after the updates (this is because tuning is performed
- * at best effort).
- * \todo params that could not be updated are not marked here, so are
- * confusing - are they "existing" values or intended to be configured
- * values?
- * \param[in] mayBlock if true (C2_MAY_BLOCK), implementation may momentarily block.
- * Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
- * \param[out] failures a list of parameter failures and optional guidance
- *
- * \retval C2_OK all parameters could be updated successfully
- * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
- * parameters were not supported
- * \retval C2_BAD_VALUE some supported parameters could not be updated successfully because
- * they contained unsupported values. These are returned in |failures|.
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_NO_MEMORY some supported parameters could not be updated successfully because
- * they contained unsupported values, but could not allocate a failure
- * object for them.
- * \retval C2_TIMED_OUT could not set the parameters within the time limit (unexpected)
- * (this error code is only allowed for interfaces connected to components
- * in the running state)
- * \retval C2_BLOCKING the operation must block to complete but mayBlock is false
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
- * (unexpected)
- * (this error code is only allowed for interfaces connected to components)
- */
- virtual c2_status_t config_vb(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
-
- // TUNNELING
- // =============================================================================================
-
- /**
- * Creates a tunnel from this component to the target component.
- *
- * If the component is successfully created, subsequent work items queued may include a
- * tunneled path between these components.
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- *
- * This method may be momentarily blocking, but MUST return within 5ms.
- *
- * \retval C2_OK the tunnel was successfully created
- * \retval C2_BAD_INDEX the target component does not exist
- * \retval C2_DUPLICATE the tunnel already exists
- * \retval C2_OMITTED tunneling is not supported by this component
- * \retval C2_CANNOT_DO the specific tunnel is not supported
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- *
- * \retval C2_TIMED_OUT could not create the tunnel within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the tunnel (unexpected)
- * (this error code is only allowed for interfaces connected to components)
- */
- virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) = 0;
-
- /**
- * Releases a tunnel from this component to the target component.
- *
- * The release of a tunnel is delayed while there are pending work items for the tunnel.
- * After releasing a tunnel, subsequent work items queued MUST NOT include a tunneled
- * path between these components.
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- *
- * This method may be momentarily blocking, but MUST return within 5ms.
- *
- * \retval C2_OK the tunnel was marked for release successfully
- * \retval C2_BAD_INDEX the target component does not exist
- * \retval C2_NOT_FOUND the tunnel does not exist
- * \retval C2_OMITTED tunneling is not supported by this component
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- *
- * \retval C2_TIMED_OUT could not mark the tunnel for release within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the release of the tunnel (unexpected)
- * (this error code is only allowed for interfaces connected to components)
- */
- virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) = 0;
-
- // REFLECTION MECHANISM (USED FOR EXTENSION)
- // =============================================================================================
-
- /**
- * Returns the set of supported parameters.
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \param[out] params a vector of supported parameters will be appended to this vector.
- *
- * \retval C2_OK the operation completed successfully.
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_NO_MEMORY not enough memory to complete this method.
- */
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
-
- /**
- * Retrieves the supported values for the queried fields.
- *
- * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
- * currently supported values, or potential supported values) in fields.
- * Upon return the component SHALL fill in the supported values for the fields listed as well
- * as a status for each field. Component shall process all fields queried even if some queries
- * fail.
- *
- * When attached to a component, this method MUST be supported in any component state except
- * released.
- *
- * This method has a variable blocking behavior based on state.
- * In the stopped state this method MUST be "non-blocking" and return within 1ms.
- * In the running states this method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param[in out] fields a vector of fields descriptor structures.
- * \param[in] mayBlock if true (C2_MAY_BLOCK), implementation may momentarily block.
- * Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
- *
- * \retval C2_OK the operation completed successfully.
- * \retval C2_BAD_STATE when called in the released component state (user error)
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_BAD_INDEX at least one field was not recognized as a component field
- * \retval C2_TIMED_OUT could not query supported values within the time limit (unexpected)
- * (this error code is only allowed for interfaces connected to components
- * in the running state)
- * \retval C2_BLOCKING the operation must block to complete but mayBlock is false
- * (this error code is only allowed for interfaces connected to components)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- * (this error code is only allowed for interfaces connected to components)
- */
- virtual c2_status_t querySupportedValues_vb(
- std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const = 0;
-
- virtual ~C2ComponentInterface() = default;
-};
-
-class C2Component {
-public:
- class Listener {
- public:
- virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,
- std::list<std::unique_ptr<C2Work>> workItems) = 0;
-
- virtual void onTripped_nb(std::weak_ptr<C2Component> component,
- std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;
-
- virtual void onError_nb(std::weak_ptr<C2Component> component,
- uint32_t errorCode) = 0;
-
- // virtual void onTunnelReleased(<from>, <to>) = 0;
-
- // virtual void onComponentReleased(<id>) = 0;
-
- virtual ~Listener() = default;
- };
-
- /**
- * Sets the listener for this component
- *
- * This method MUST be supported in all states except released.
- * The listener can only be set to non-null value in stopped state (that does not include
- * tripped or error). It can be set to nullptr in both stopped and running states.
- * Components only use the listener in running state.
- *
- * If listener is nullptr, the component SHALL guarantee that no more listener callbacks are
- * done to the original listener once this method returns. (Any pending listener callbacks will
- * need to be completed during this call - hence this call may be temporarily blocking.)
- *
- * This method has a variable blocking behavior based on state.
- * In the stopped state this method MUST be "non-blocking" and return within 1ms.
- * In the running states this method may be momentarily blocking, but MUST return within 5ms.
- *
- * Component SHALL handle listener notifications from the same thread (the thread used is
- * at the component's discretion.)
- *
- * \note This could also be accomplished by passing a weak_ptr to a component-specific listener
- * here and requiring the client to always promote the weak_ptr before any callback. This would
- * put the burden on the client to clear the listener - wait for its deletion - at which point
- * it is guaranteed that no more listener callbacks will occur.
- *
- * \param[in] listener the component listener object
- * \param[in] mayBlock if true (C2_MAY_BLOCK), implementation may momentarily block.
- * Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
- *
- * \retval C2_BAD_STATE attempting to change the listener in the running state to a non-null
- * value (user error), or called in the released state
- * \retval C2_BLOCKING the operation must block to complete but mayBlock is false
- * \retval C2_OK listener was updated successfully.
- */
- virtual c2_status_t setListener_vb(
- const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) = 0;
-
- enum domain_t : uint32_t;
- enum kind_t : uint32_t;
- typedef uint32_t rank_t;
-
- /**
- * Information about a component.
- */
- struct Traits {
- // public:
- C2String name; ///< name of the component
- domain_t domain; ///< component domain (e.g. audio or video)
- kind_t kind; ///< component kind (e.g. encoder, decoder or filter)
- rank_t rank; ///< rank used to determine component ordering (the lower the sooner)
- C2String mediaType; ///< media type supported by the component
-
- /**
- * name alias(es) for backward compatibility.
- * \note Multiple components can have the same alias as long as their media-type differs.
- */
- std::vector<C2StringLiteral> aliases; ///< name aliases for backward compatibility
- };
-
- // METHODS AVAILABLE WHEN RUNNING
- // =============================================================================================
-
- /**
- * Queues up work for the component.
- *
- * This method MUST be supported in running (including tripped and error) states.
- *
- * This method MUST be "non-blocking" and return within 1 ms
- *
- * It is acceptable for this method to return OK and return an error value using the
- * onWorkDone() callback.
- *
- * \retval C2_OK the work was successfully queued
- * \retval C2_BAD_INDEX some component(s) in the work do(es) not exist
- * \retval C2_CANNOT_DO the components are not tunneled
- * \retval C2_BAD_STATE when called in the stopped or released state (user error)
- *
- * \retval C2_NO_MEMORY not enough memory to queue the work
- * \retval C2_CORRUPTED some unknown error prevented queuing the work (unexpected)
- */
- virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) = 0;
-
- /**
- * Announces a work to be queued later for the component. This reserves a slot for the queue
- * to ensure correct work ordering even if the work is queued later.
- *
- * This method MUST be supported in running (including tripped and error) states.
- *
- * This method MUST be "non-blocking" and return within 1 ms
- *
- * \retval C2_OK the work announcement has been successfully recorded
- * \retval C2_BAD_INDEX some component(s) in the work outline do(es) not exist
- * \retval C2_CANNOT_DO the componentes are not tunneled
- * \retval C2_BAD_STATE when called in the stopped or released state (user error)
- *
- * \retval C2_NO_MEMORY not enough memory to record the work announcement
- * \retval C2_CORRUPTED some unknown error prevented recording the announcement (unexpected)
- *
- * \todo Can this be rolled into queue_nb?
- * \todo Expose next work item for each component to detect stalls
- */
- virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;
-
- enum flush_mode_t : uint32_t {
- /// flush work from this component only
- FLUSH_COMPONENT,
-
- /// flush work from this component and all components connected downstream from it via
- /// tunneling
- FLUSH_CHAIN = (1 << 16),
- };
-
- /**
- * Discards and abandons any pending work for the component, and optionally any component
- * downstream.
- *
- * \todo define this: we could flush all work before last item queued for component across all
- * components linked to this; flush only work items that are queued to this
- * component
- * \todo return work # of last flushed item; or all flushed (but not returned items)
- * \todo we could make flush take a work item and flush all work before/after that item to allow
- * TBD (slicing/seek?)
- * \todo we could simply take a list of numbers and flush those... this is bad for decoders
- * also, what would happen to fine grade references?
- *
- * This method MUST be supported in running (including tripped and error) states.
- *
- * This method may be momentarily blocking, but must return within 5ms.
- *
- * Work that could be immediately abandoned/discarded SHALL be returned in |flushedWork|; this
- * can be done in an arbitrary order.
- *
- * Work that could not be abandoned or discarded immediately SHALL be marked to be
- * discarded at the earliest opportunity, and SHALL be returned via the onWorkDone() callback.
- * This shall be completed within 500ms.
- *
- * \param mode flush mode
- *
- * \retval C2_OK the component has been successfully flushed
- * \retval C2_BAD_STATE when called in the stopped or released state (user error)
- * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
- */
- virtual c2_status_t flush_sm(flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) = 0;
-
- enum drain_mode_t : uint32_t {
- /// drain component only and add an "end-of-stream" marker. Component shall process all
- /// queued work and complete the current stream. If new input is received, it shall start
- /// a new stream. \todo define what a stream is.
- DRAIN_COMPONENT_WITH_EOS,
- /// drain component without setting "end-of-stream" marker. Component shall process all
- /// queued work but shall expect more work items for the same stream.
- DRAIN_COMPONENT_NO_EOS = (1 << 0),
-
- /// marks the last work item with a persistent "end-of-stream" marker that will drain
- /// downstream components
- /// \todo this may confuse work-ordering downstream
- DRAIN_CHAIN = (1 << 16),
-
- /**
- * \todo define this; we could place EOS to all upstream components, just this component, or
- * all upstream and downstream component.
- * \todo should EOS carry over to downstream components?
- */
- };
-
- /**
- * Drains the component, and optionally downstream components. This is a signalling method;
- * as such it does not wait for any work completion.
- *
- * Marks last work item as "drain-till-here", so component is notified not to wait for further
- * work before it processes work already queued. This method can also used to set the
- * end-of-stream flag after work has been queued. Client can continue to queue further work
- * immediately after this method returns.
- *
- * This method MUST be supported in running (including tripped) states.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * Work that is completed SHALL be returned via the onWorkDone() callback.
- *
- * \param mode drain mode
- *
- * \retval C2_OK the drain request has been successfully recorded
- * \retval C2_BAD_STATE when called in the stopped or released state (user error)
- * \retval C2_BAD_VALUE the drain mode is not supported by the component
- * \todo define supported modes discovery
- * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
- */
- virtual c2_status_t drain_nb(drain_mode_t mode) = 0;
-
- // STATE CHANGE METHODS
- // =============================================================================================
-
- /**
- * Starts the component.
- *
- * This method MUST be supported in stopped state, as well as during the tripped state.
- *
- * If the return value is C2_OK, the component shall be in the running state.
- * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
- * response to this call.
- * Otherwise, the component shall be in the stopped state.
- *
- * \note If a component is in the tripped state and start() is called while the component
- * configuration still results in a trip, start shall succeed and a new onTripped callback
- * should be used to communicate the configuration conflict that results in the new trip.
- *
- * \todo This method MUST return within 500ms. Seems this should be able to return quickly, as
- * there are no immediate guarantees. Though there are guarantees for responsiveness immediately
- * after start returns.
- *
- * \retval C2_OK the component has started (or resumed) successfully
- * \retval C2_DUPLICATE when called during another start call from another thread
- * \retval C2_BAD_STATE when called in any state other than the stopped state or tripped state,
- * including when called during another state change call from another
- * thread (user error)
- * \retval C2_NO_MEMORY not enough memory to start the component
- * \retval C2_TIMED_OUT the component could not be started within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented starting the component (unexpected)
- */
- virtual c2_status_t start() = 0;
-
- /**
- * Stops the component.
- *
- * This method MUST be supported in running (including tripped) state.
- *
- * This method MUST return withing 500ms.
- *
- * Upon this call, all pending work SHALL be abandoned and all buffer references SHALL be
- * released.
- * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
- * response to this call.
- * For all other return values, the component shall be in the stopped state.
- *
- * \todo should this return completed work, since client will just free it? Perhaps just to
- * verify accounting.
- *
- * This does not alter any settings and tunings that may have resulted in a tripped state.
- * (Is this material given the definition? Perhaps in case we want to start again.)
- *
- * \retval C2_OK the component has started successfully
- * \retval C2_DUPLICATE when called during another stop call from another thread
- * \retval C2_BAD_STATE when called in any state other than the running state, including when
- * called during another state change call from another thread (user error)
- * \retval C2_TIMED_OUT the component could not be stopped within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented stopping the component (unexpected)
- */
- virtual c2_status_t stop() = 0;
-
- /**
- * Resets the component.
- *
- * This method MUST be supported in all (including tripped) states other than released.
- *
- * This method MUST be supported during any other blocking call.
- *
- * This method MUST return withing 500ms.
- *
- * After this call returns all work SHALL be abandoned, all buffer references SHALL be released.
- * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
- * response to this call.
- * For all other return values, the component shall be in the stopped state.
- *
- * \todo should this return completed work, since client will just free it? Also, if it unblocks
- * a stop, where should completed work be returned?
- *
- * This brings settings back to their default - "guaranteeing" no tripped space.
- *
- * \todo reclaim support - it seems that since ownership is passed, this will allow reclaiming
- * stuff.
- *
- * \retval C2_OK the component has been reset
- * \retval C2_DUPLICATE when called during another reset call from another thread
- * \retval C2_BAD_STATE when called in the released state
- * \retval C2_TIMED_OUT the component could not be reset within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented resetting the component (unexpected)
- */
- virtual c2_status_t reset() = 0;
-
- /**
- * Releases the component.
- *
- * This method MUST be supported in stopped state.
- *
- * This method MUST return withing 500ms. Upon return all references shall be abandoned.
- *
- * \retval C2_OK the component has been released
- * \retval C2_DUPLICATE the component is already released
- * \retval C2_BAD_STATE the component is running
- * \retval C2_TIMED_OUT the component could not be released within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented releasing the component (unexpected)
- */
- virtual c2_status_t release() = 0;
-
- /**
- * Returns the interface for this component.
- *
- * \return the component interface
- */
- virtual std::shared_ptr<C2ComponentInterface> intf() = 0;
-
- virtual ~C2Component() = default;
-};
-
-class C2FrameInfoParser {
-public:
- /**
- * \return the content type supported by this info parser.
- *
- * \todo this may be redundant
- */
- virtual C2StringLiteral getType() const = 0;
-
- /**
- * \return a vector of supported parameter indices parsed by this info parser.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \todo sticky vs. non-sticky params? this may be communicated by param-reflector.
- */
- virtual const std::vector<C2Param::Index> getParsedParams() const = 0;
-
- /**
- * Resets this info parser. This brings this parser to its initial state after creation.
- *
- * This method SHALL return within 5ms.
- *
- * \retval C2_OK the info parser was reset
- * \retval C2_TIMED_OUT could not reset the parser within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the resetting of the parser (unexpected)
- */
- virtual c2_status_t reset() { return C2_OK; }
-
- virtual c2_status_t parseFrame(C2FrameData &frame);
-
- virtual ~C2FrameInfoParser() = default;
-};
-
-class C2AllocatorStore {
-public:
- typedef C2Allocator::id_t id_t;
-
- enum : C2Allocator::id_t {
- DEFAULT_LINEAR, ///< basic linear allocator type
- DEFAULT_GRAPHIC, ///< basic graphic allocator type
- PLATFORM_START = 0x10,
- VENDOR_START = 0x100,
- BAD_ID = C2Allocator::BAD_ID, ///< DO NOT USE
- };
-
- /**
- * Returns the unique name of this allocator store.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the name of this allocator store.
- * \retval an empty string if there was not enough memory to allocate the actual name.
- */
- virtual C2String getName() const = 0;
-
- /**
- * Returns the set of allocators supported by this allocator store.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \retval vector of allocator information (as shared pointers)
- * \retval an empty vector if there was not enough memory to allocate the whole vector.
- */
- virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb() const = 0;
-
- /**
- * Retrieves/creates a shared allocator object.
- *
- * This method MUST be return within 5ms.
- *
- * The allocator is created on first use, and the same allocator is returned on subsequent
- * concurrent uses in the same process. The allocator is freed when it is no longer referenced.
- *
- * \param id the ID of the allocator to create. This is defined by the store, but
- * the ID of the default linear and graphic allocators is formalized.
- * \param allocator shared pointer where the created allocator is stored. Cleared on failure
- * and updated on success.
- *
- * \retval C2_OK the allocator was created successfully
- * \retval C2_TIMED_OUT could not create the allocator within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the allocator (unexpected)
- *
- * \retval C2_NOT_FOUND no such allocator
- * \retval C2_NO_MEMORY not enough memory to create the allocator
- */
- virtual c2_status_t fetchAllocator(id_t id, std::shared_ptr<C2Allocator>* const allocator) = 0;
-
- virtual ~C2AllocatorStore() = default;
-};
-
-class C2ComponentStore {
-public:
- /**
- * Returns the name of this component or component interface object.
- * This is a unique name for this component or component interface 'class'; however, multiple
- * instances of this component SHALL have the same name.
- *
- * This method MUST be supported in any state. This call does not change the state nor the
- * internal states of the component.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the name of this component or component interface object.
- * \retval an empty string if there was not enough memory to allocate the actual name.
- */
- virtual C2String getName() const = 0;
-
- /**
- * Creates a component.
- *
- * This method SHALL return within 100ms.
- *
- * \param name name of the component to create
- * \param component shared pointer where the created component is stored. Cleared on
- * failure and updated on success.
- *
- * \retval C2_OK the component was created successfully
- * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
- *
- * \retval C2_NOT_FOUND no such component
- * \retval C2_NO_MEMORY not enough memory to create the component
- */
- virtual c2_status_t createComponent(
- C2String name, std::shared_ptr<C2Component>* const component) = 0;
-
- /**
- * Creates a component interface.
- *
- * This method SHALL return within 100ms.
- *
- * \param name name of the component interface to create
- * \param interface shared pointer where the created interface is stored
- *
- * \retval C2_OK the component interface was created successfully
- * \retval C2_TIMED_OUT could not create the component interface within the time limit
- * (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
- * (unexpected)
- *
- * \retval C2_NOT_FOUND no such component interface
- * \retval C2_NO_MEMORY not enough memory to create the component interface
- *
- * \todo Do we need an interface, or could this just be a component that is never started?
- */
- virtual c2_status_t createInterface(
- C2String name, std::shared_ptr<C2ComponentInterface>* const interface) = 0;
-
- /**
- * Returns the list of components supported by this component store.
- *
- * This method MUST return within 500ms.
- *
- * \retval vector of component information.
- */
- virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() = 0;
-
- // -------------------------------------- UTILITY METHODS --------------------------------------
-
- // on-demand buffer layout conversion (swizzling)
- //
- virtual c2_status_t copyBuffer(
- std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) = 0;
-
- // -------------------------------------- CONFIGURATION API -----------------------------------
- // e.g. for global settings (system-wide stride, etc.)
-
- /**
- * Queries a set of system-wide parameters.
- * Querying is performed at best effort: the store SHALL query all supported parameters and
- * skip unsupported ones, or heap allocated parameters that could not be allocated. Any errors
- * are communicated in the return value. Additionally, preallocated (e.g. stack) parameters that
- * could not be queried are invalidated. Parameters to be allocated on the heap are omitted from
- * the result.
- *
- * \note Parameter values do not depend on the order of query.
- *
- * This method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param stackParams a list of params queried. These are initialized specific to each
- * setting; e.g. size and index are set and rest of the members are
- * cleared.
- * NOTE: Flexible settings that are of incorrect size will be invalidated.
- * \param heapParamIndices a vector of param indices for params to be queried and returned on the
- * heap. These parameters will be returned in heapParams. Unsupported param
- * indices will be ignored.
- * \param heapParams a list of params where to which the supported heap parameters will be
- * appended in the order they appear in heapParamIndices.
- *
- * \retval C2_OK all parameters could be queried
- * \retval C2_BAD_INDEX all supported parameters could be queried, but some parameters were not
- * supported
- * \retval C2_NO_MEMORY could not allocate memory for a supported parameter
- * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
- * (unexpected)
- */
- virtual c2_status_t query_sm(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
-
- /**
- * Sets a set of system-wide parameters.
- *
- * \note There are no settable system-wide parameters defined thus far, but may be added in the
- * future.
- *
- * Tuning is performed at best effort: the store SHALL update all supported configuration at
- * best effort (unless configured otherwise) and skip unsupported ones. Any errors are
- * communicated in the return value and in |failures|.
- *
- * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
- * update may allow some subsequent parameter update.
- *
- * This method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param params a list of parameter updates. These will be updated to the actual
- * parameter values after the updates (this is because tuning is performed
- * at best effort).
- * \todo params that could not be updated are not marked here, so are
- * confusing - are they "existing" values or intended to be configured
- * values?
- * \param failures a list of parameter failures
- *
- * \retval C2_OK all parameters could be updated successfully
- * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
- * parameters were not supported
- * \retval C2_BAD_VALUE some supported parameters could not be updated successfully because
- * they contained unsupported values. These are returned in |failures|.
- * \retval C2_NO_MEMORY some supported parameters could not be updated successfully because
- * they contained unsupported values, but could not allocate a failure
- * object for them.
- * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
- * (unexpected)
- */
- virtual c2_status_t config_sm(
- const std::vector<C2Param*> ¶ms,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
-
- // REFLECTION MECHANISM (USED FOR EXTENSION)
- // =============================================================================================
-
- /**
- * Returns the parameter reflector.
- *
- * This is used to describe parameter fields. This is shared for all components created by
- * this component store.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a shared parameter reflector object.
- */
- virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;
-
- /**
- * Returns the set of supported parameters.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \param[out] params a vector of supported parameters will be appended to this vector.
- *
- * \retval C2_OK the operation completed successfully.
- * \retval C2_NO_MEMORY not enough memory to complete this method.
- */
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
-
- /**
- * Retrieves the supported values for the queried fields.
- *
- * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
- * currently supported values, or potential supported values) in fields.
- * Upon return the store SHALL fill in the supported values for the fields listed as well
- * as a status for each field. Store shall process all fields queried even if some queries
- * fail.
- *
- * This method may be momentarily blocking, but MUST return within 5ms.
- *
- * \param[in out] fields a vector of fields descriptor structures.
- *
- * \retval C2_OK the operation completed successfully.
- * \retval C2_BAD_INDEX at least one field was not recognized as a component store field
- */
- virtual c2_status_t querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery> &fields) const = 0;
-
- virtual ~C2ComponentStore() = default;
-};
-
-// ================================================================================================
-
-/// @}
-
-#endif // C2COMPONENT_H_
diff --git a/media/libstagefright/codec2/include/C2Config.h b/media/libstagefright/codec2/include/C2Config.h
deleted file mode 100644
index 3f149bb..0000000
--- a/media/libstagefright/codec2/include/C2Config.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2CONFIG_H_
-#define C2CONFIG_H_
-
-#include <C2ParamDef.h>
-
-/// \defgroup config Component configuration
-/// @{
-
-#ifndef DEFINE_C2_ENUM_VALUE_AUTO_HELPER
-#define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...)
-#define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, ...)
-#endif
-
-#define C2ENUM(name, type, ...) \
-enum name : type { __VA_ARGS__ }; \
-DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, NULL, __VA_ARGS__)
-
-#define C2ENUM_CUSTOM_PREFIX(name, type, prefix, ...) \
-enum name : type { __VA_ARGS__ }; \
-DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, __VA_ARGS__)
-
-#define C2ENUM_CUSTOM_NAMES(name, type, names, ...) \
-enum name : type { __VA_ARGS__ }; \
-DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, __VA_ARGS__)
-
-enum C2ParamIndexKind : C2Param::type_index_t {
- /// domain
- kParamIndexDomain,
-
- /// configuration descriptors
- kParamIndexSupportedParams,
- kParamIndexRequiredParams,
- kParamIndexReadOnlyParams,
- kParamIndexRequestedInfos,
-
- /// latency
- kParamIndexLatency,
-
- // generic time behavior
- kParamIndexTemporal,
-
- /// port configuration
- kParamIndexMime,
- kParamIndexStreamCount,
- kParamIndexFormat,
- kParamIndexBlockPools,
-
- kParamIndexMaxVideoSizeHint,
- kParamIndexVideoSizeTuning,
-
- kParamIndexCsd,
- kParamIndexPictureTypeMask,
-
- // video info
-
- kParamIndexStructStart = 0x1,
- kParamIndexVideoSize,
-
- kParamIndexParamStart = 0x800,
-};
-
-C2ENUM(C2DomainKind, uint32_t,
- C2DomainVideo,
- C2DomainAudio,
- C2DomainOther = C2DomainAudio + 1
-);
-
-// read-only
-
-typedef C2GlobalParam<C2Info, C2SimpleValueStruct<C2DomainKind>, kParamIndexDomain> C2ComponentDomainInfo;
-// typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexDomain> C2ComponentDomainInfo;
-//DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<C2DomainKind>, { C2FIELD(mValue, "value") });
-
-// read-only
-typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexSupportedParams> C2SupportedParamsInfo;
-
-/// \todo do we define it as a param?
-// read-only
-typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexRequiredParams> C2RequiredParamsInfo;
-
-// read-only
-typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexReadOnlyParams> C2ReadOnlyParamsInfo;
-
-// read-only
-typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexRequestedInfos> C2RequestedInfosInfo;
-
-// read-only
-//typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexRequestedInfos> C2RequestedInfosInfo;
-
-/// latency
-
-typedef C2PortParam<C2Info, C2Uint32Value, kParamIndexLatency> C2PortLatencyInfo;
-
-typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexLatency> C2ComponentLatencyInfo;
-
-/// \todo
-typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexTemporal> C2ComponentTemporalInfo;
-
-/// port configuration
-
-typedef C2PortParam<C2Tuning, C2StringValue, kParamIndexMime> C2PortMimeConfig;
-
-typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexStreamCount> C2PortStreamCountConfig;
-
-typedef C2StreamParam<C2Tuning, C2StringValue, kParamIndexMime> C2StreamMimeConfig;
-
-C2ENUM(C2FormatKind, uint32_t,
- C2FormatCompressed,
- C2FormatAudio = 1,
- C2FormatVideo = 4,
-)
-
-typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexFormat> C2StreamFormatConfig;
-
-typedef C2PortParam<C2Tuning, C2Uint64Array, kParamIndexBlockPools> C2PortBlockPoolsTuning;
-
-typedef C2StreamParam<C2Info, C2BlobValue, kParamIndexCsd> C2StreamCsdInfo;
-
-C2ENUM(C2PictureTypeMask, uint32_t,
- C2PictureTypeKeyFrame = (1u << 0),
-)
-
-typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexPictureTypeMask> C2StreamPictureTypeMaskInfo;
-
-/*
- Component description fields:
-
-// format (video/compressed/audio/other-do we need other?) per stream
-
-// likely some of these are exposed as separate settings:
-
-struct C2BaseTuning {
- // latency characteristics
- uint32_t latency;
- bool temporal; // seems this only makes sense if latency is 1..., so this could be captured as latency = 0
- uint32_t delay;
-
- uint32_t numInputStreams; // RW? - or suggestion only: RO
- uint32_t numOutputStreams; // RW
- //
- // refs characteristics (per stream?)
- uint32_t maxInputRefs; // RO
- uint32_t maxOutputRefs; // RO
- uint32_t maxInputMemory; // RO - max time refs are held for
- uint32_t maxOutputMemory; // RO
-
- // per stream
- bool compressed;
- // format... video/compressed/audio/other?
- // actual "audio/video" format type
- uint32_t width/height? is this needed, or just queue...
- // mime...
-};
-*/
-
-
-
-
-
-
-// overall component
-// => C: domain: audio or video
-// => C: kind: decoder, encoder or filter
-// => "mime" class
-
-// => C: temporal (bool) => does this depend on ordering?
-// => I: latency
-// => I: history max duration...
-// => I: history max frames kept...
-// => I: reordering depth
-// => I: frc (bool) (perhaps ratio?)
-// => I: current frc
-
-// - pause
-// => last frame 'number' processed
-// => current frame 'number' processed
-// => invalid settings =>[]
-
-// video decoder configuration: // audio
-// - encoding // -encoding
-// - hint: max width/height // -hint: sample rate, channels
-// - hint: profile/level // -hint: tools used
-// - hint: framerate (bitrate?) // -hint: bitrate
-// - default: color space (from container)
-// - hint: color format // -hint: pcm-encoding
-// - hint: # of views (e.g. MVC) // -hint?: channel groups
-// - default: HDR static info (from container) // -hint?: channel mappings
-// - hint: rotation (e.g. for allocator)
-
-// => # of streams required and their formats? (setting?)
-// => # of streams produced and their formats? (tuning)
-
-// => output
-// - # of views // -channel groups && channel mappings
-// - width/height/crop/color format/color space/HDR static info (from buffers)
-// (as required by the allocator & framework)
-// - SEI (or equivalent) <= [port]
-// - CC
-// - reference info
-
-// video encoder configurations
-// - encoding // - encoding
-// - hint: width/height // - hint: sample rate, channels
-// - hint: frame rate
-// - hint: max width/height (? does this differ from width/height?)
-// - # of input (e.g. MVC) // - hint: # groups and mappings
-// - # of output (e.g. SVC) => bitrates/width/height/framerates? per stream
-// - hint: profile/level // - hint: profile/level
-// - HDR static info + (info: HDR)
-// - color space
-// - hint: color format? // - hint: pcm encoding
-// - SEI
-// - CC
-// - reference directive
-// - hint: bitrate (or quality) // - hint: bitrate/quality
-// - optional: codec-specific parameters // - optional: csd
-
-// => output // => output
-// - layers per stream? // E-AC3?... DTS?...Dolby-Vision?
-// - reference info
-
-
-// RM:
-// - need SPS for full knowledge => component should return max. (component can use less)
-// - critical parameters? (interlaced? profile? level?)
-
-struct C2VideoSizeStruct {
- int32_t width; ///< video width
- int32_t height; ///< video height
-
- DEFINE_AND_DESCRIBE_BASE_C2STRUCT(VideoSize)
- C2FIELD(width, "width")
- C2FIELD(height, "height")
-};
-
-// video size for video decoder [OUT]
-typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexVideoSize> C2VideoSizeStreamInfo;
-
-// max video size for video decoder [IN]
-typedef C2PortParam<C2Setting, C2VideoSizeStruct, kParamIndexMaxVideoSizeHint> C2MaxVideoSizeHintPortSetting;
-
-// video encoder size [IN]
-typedef C2StreamParam<C2Tuning, C2VideoSizeStruct, kParamIndexVideoSizeTuning> C2VideoSizeStreamTuning;
-
-/// @}
-
-#endif
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
deleted file mode 100644
index e0a743c..0000000
--- a/media/libstagefright/codec2/include/C2Param.h
+++ /dev/null
@@ -1,1470 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2PARAM_H_
-#define C2PARAM_H_
-
-#include <C2.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-/// \addtogroup Parameters
-/// @{
-
-/// \defgroup internal Internal helpers.
-
-/*!
- * \file
- * PARAMETERS: SETTINGs, TUNINGs, and INFOs
- * ===
- *
- * These represent miscellaneous control and metadata information and are likely copied into
- * kernel space. Therefore, these are C-like structures designed to carry just a small amount of
- * information. We are using C++ to be able to add constructors, as well as non-virtual and class
- * methods.
- *
- * ==Specification details:
- *
- * Restrictions:
- * - must be POD struct, e.g. no vtable (no virtual destructor)
- * - must have the same size in 64-bit and 32-bit mode (no size_t)
- * - as such, no pointer members
- * - some common member field names are reserved as they are defined as methods for all
- * parameters:
- * they are: size, type, kind, index and stream
- *
- * Behavior:
- * - Params can be global (not related to input or output), related to input or output,
- * or related to an input/output stream.
- * - All params are queried/set using a unique param index, which incorporates a potential stream
- * index and/or port.
- * - Querying (supported) params MUST never fail.
- * - All params MUST have default values.
- * - If some fields have "unsupported" or "invalid" values during setting, this SHOULD be
- * communicated to the app.
- * a) Ideally, this should be avoided. When setting parameters, in general, component should do
- * "best effort" to apply all settings. It should change "invalid/unsupported" values to the
- * nearest supported values.
- * - This is communicated to the client by changing the source values in tune()/
- * configure().
- * b) If falling back to a supported value is absolutely impossible, the component SHALL return
- * an error for the specific setting, but should continue to apply other settings.
- * TODO: this currently may result in unintended results.
- *
- * **NOTE:** unlike OMX, params are not versioned. Instead, a new struct with new param index
- * SHALL be added as new versions are required.
- *
- * The proper subtype (Setting, Info or Param) is incorporated into the class type. Define structs
- * to define multiple subtyped versions of related parameters.
- *
- * ==Implementation details:
- *
- * - Use macros to define parameters
- * - All parameters must have a default constructor
- * - This is only used for instantiating the class in source (e.g. will not be used
- * when building a parameter by the framework from key/value pairs.)
- */
-
-/// \ingroup internal
-
-/**
- * Parameter base class.
- */
-struct C2Param {
- // param index encompasses the following:
- //
- // - kind (setting, tuning, info, struct)
- // - scope
- // - direction (global, input, output)
- // - stream flag
- // - stream ID (usually 0)
- // - and the parameter's type (core index)
- // - flexible parameter flag
- // - vendor extension flag
- // - type index (this includes the vendor extension flag)
- //
- // layout:
- //
- // kind : <------- scope -------> : <----- core index ----->
- // +------+-----+---+------+--------+----|------+--------------+
- // | kind | dir | - |stream|streamID|flex|vendor| type index |
- // +------+-----+---+------+--------+----+------+--------------+
- // bit: 31..30 29.28 25 24 .. 17 16 15 14 .. 0
- //
-public:
- /**
- * C2Param kinds, usable as bitmaps.
- */
- enum kind_t : uint32_t {
- NONE = 0,
- STRUCT = (1 << 0),
- INFO = (1 << 1),
- SETTING = (1 << 2),
- TUNING = (1 << 3) | SETTING, // tunings are settings
- };
-
- /**
- * The parameter type index specifies the underlying parameter type of a parameter as
- * an integer value.
- *
- * Parameter types are divided into two groups: platform types and vendor types.
- *
- * Platform types are defined by the platform and are common for all implementations.
- *
- * Vendor types are defined by each vendors, so they may differ between implementations.
- * It is recommended that vendor types be the same for all implementations by a specific
- * vendor.
- */
- typedef uint32_t type_index_t;
- enum : uint32_t {
- TYPE_INDEX_VENDOR_START = 0x00008000, ///< vendor indices SHALL start after this
- };
-
- /**
- * Core index is the underlying parameter type for a parameter. It is used to describe the
- * layout of the parameter structure regardless of the component or parameter kind/scope.
- *
- * It is used to identify and distinguish global parameters, and also parameters on a given
- * port or stream. They must be unique for the set of global parameters, as well as for the
- * set of parameters on each port or each stream, but the same core index can be used for
- * parameters on different streams or ports, as well as for global parameters and port/stream
- * parameters.
- *
- * Multiple parameter types can share the same layout.
- *
- * \note The layout for all parameters with the same core index across all components must
- * be identical.
- */
- struct CoreIndex {
- //public:
- enum : uint32_t {
- IS_FLEX_FLAG = 0x00010000,
- };
-
- protected:
- enum : uint32_t {
- KIND_MASK = 0xC0000000,
- KIND_STRUCT = 0x00000000,
- KIND_TUNING = 0x40000000,
- KIND_SETTING = 0x80000000,
- KIND_INFO = 0xC0000000,
-
- DIR_MASK = 0x30000000,
- DIR_GLOBAL = 0x20000000,
- DIR_UNDEFINED = DIR_MASK, // MUST have all bits set
- DIR_INPUT = 0x00000000,
- DIR_OUTPUT = 0x10000000,
-
- IS_STREAM_FLAG = 0x02000000,
- STREAM_ID_MASK = 0x01FE0000,
- STREAM_ID_SHIFT = 17,
- MAX_STREAM_ID = STREAM_ID_MASK >> STREAM_ID_SHIFT,
- STREAM_MASK = IS_STREAM_FLAG | STREAM_ID_MASK,
-
- IS_VENDOR_FLAG = 0x00008000,
- TYPE_INDEX_MASK = 0x0000FFFF,
- CORE_MASK = TYPE_INDEX_MASK | IS_FLEX_FLAG,
- };
-
- public:
- /// constructor/conversion from uint32_t
- inline CoreIndex(uint32_t index) : mIndex(index) { }
-
- // no conversion from uint64_t
- inline CoreIndex(uint64_t index) = delete;
-
- /// returns true iff this is a vendor extension parameter
- inline bool isVendor() const { return mIndex & IS_VENDOR_FLAG; }
-
- /// returns true iff this is a flexible parameter (with variable size)
- inline bool isFlexible() const { return mIndex & IS_FLEX_FLAG; }
-
- /// returns the core index
- /// This is the combination of the parameter type index and the flexible flag.
- inline uint32_t coreIndex() const { return mIndex & CORE_MASK; }
-
- /// returns the parameter type index
- inline type_index_t typeIndex() const { return mIndex & TYPE_INDEX_MASK; }
-
- DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(CoreIndex, mIndex, CORE_MASK)
-
- protected:
- uint32_t mIndex;
- };
-
- /**
- * Type encompasses the parameter's kind (tuning, setting, info), its scope (whether the
- * parameter is global, input or output, and whether it is for a stream) and the its base
- * index (which also determines its layout).
- */
- struct Type : public CoreIndex {
- //public:
- /// returns true iff this is a global parameter (not for input nor output)
- inline bool isGlobal() const { return (mIndex & DIR_MASK) == DIR_GLOBAL; }
- /// returns true iff this is an input or input stream parameter
- inline bool forInput() const { return (mIndex & DIR_MASK) == DIR_INPUT; }
- /// returns true iff this is an output or output stream parameter
- inline bool forOutput() const { return (mIndex & DIR_MASK) == DIR_OUTPUT; }
-
- /// returns true iff this is a stream parameter
- inline bool forStream() const { return mIndex & IS_STREAM_FLAG; }
- /// returns true iff this is a port (input or output) parameter
- inline bool forPort() const { return !forStream() && !isGlobal(); }
-
- /// returns the parameter type: the parameter index without the stream ID
- inline uint32_t type() const { return mIndex & (~STREAM_ID_MASK); }
-
- /// return the kind (struct, info, setting or tuning) of this param
- inline kind_t kind() const {
- switch (mIndex & KIND_MASK) {
- case KIND_STRUCT: return STRUCT;
- case KIND_INFO: return INFO;
- case KIND_SETTING: return SETTING;
- case KIND_TUNING: return TUNING;
- default: return NONE; // should not happen
- }
- }
-
- /// constructor/conversion from uint32_t
- inline Type(uint32_t index) : CoreIndex(index) { }
-
- // no conversion from uint64_t
- inline Type(uint64_t index) = delete;
-
- DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(Type, mIndex, ~STREAM_ID_MASK)
-
- private:
- friend struct C2Param; // for setPort()
- friend struct C2Tuning; // for KIND_TUNING
- friend struct C2Setting; // for KIND_SETTING
- friend struct C2Info; // for KIND_INFO
- // for DIR_GLOBAL
- template<typename T, typename S, int I, class F> friend struct C2GlobalParam;
- template<typename T, typename S, int I, class F> friend struct C2PortParam; // for kDir*
- template<typename T, typename S, int I, class F> friend struct C2StreamParam; // for kDir*
- friend struct _C2ParamInspector; // for testing
-
- /**
- * Sets the port/stream direction.
- * @return true on success, false if could not set direction (e.g. it is global param).
- */
- inline bool setPort(bool output) {
- if (isGlobal()) {
- return false;
- } else {
- mIndex = (mIndex & ~DIR_MASK) | (output ? DIR_OUTPUT : DIR_INPUT);
- return true;
- }
- }
- };
-
- /**
- * index encompasses all remaining information: basically the stream ID.
- */
- struct Index : public Type {
- /// returns the index as uint32_t
- inline operator uint32_t() const { return mIndex; }
-
- /// constructor/conversion from uint32_t
- inline Index(uint32_t index) : Type(index) { }
-
- // no conversion from uint64_t
- inline Index(uint64_t index) = delete;
-
- /// returns the stream ID or ~0 if not a stream
- inline unsigned stream() const {
- return forStream() ? rawStream() : ~0U;
- }
-
- DEFINE_FIELD_BASED_COMPARISON_OPERATORS(Index, mIndex)
-
- private:
- friend struct C2Param; // for setStream, MakeStreamId, isValid
- friend struct _C2ParamInspector; // for testing
-
- /**
- * @return true if the type is valid, e.g. direction is not undefined AND
- * stream is 0 if not a stream param.
- */
- inline bool isValid() const {
- // there is no Type::isValid (even though some of this check could be
- // performed on types) as this is only used on index...
- return (forStream() ? rawStream() < MAX_STREAM_ID : rawStream() == 0)
- && (mIndex & DIR_MASK) != DIR_UNDEFINED;
- }
-
- /// returns the raw stream ID field
- inline unsigned rawStream() const {
- return (mIndex & STREAM_ID_MASK) >> STREAM_ID_SHIFT;
- }
-
- /// returns the streamId bitfield for a given |stream|. If stream is invalid,
- /// returns an invalid bitfield.
- inline static uint32_t MakeStreamId(unsigned stream) {
- // saturate stream ID (max value is invalid)
- if (stream > MAX_STREAM_ID) {
- stream = MAX_STREAM_ID;
- }
- return (stream << STREAM_ID_SHIFT) & STREAM_ID_MASK;
- }
-
- /**
- * Sets the stream index.
- * \return true on success, false if could not set index (e.g. not a stream param).
- */
- inline bool setStream(unsigned stream) {
- if (forStream()) {
- mIndex = (mIndex & ~STREAM_ID_MASK) | MakeStreamId(stream);
- return this->stream() < MAX_STREAM_ID;
- }
- return false;
- }
- };
-
-public:
- // public getters for Index methods
-
- /// returns true iff this is a vendor extension parameter
- inline bool isVendor() const { return _mIndex.isVendor(); }
- /// returns true iff this is a flexible parameter
- inline bool isFlexible() const { return _mIndex.isFlexible(); }
- /// returns true iff this is a global parameter (not for input nor output)
- inline bool isGlobal() const { return _mIndex.isGlobal(); }
- /// returns true iff this is an input or input stream parameter
- inline bool forInput() const { return _mIndex.forInput(); }
- /// returns true iff this is an output or output stream parameter
- inline bool forOutput() const { return _mIndex.forOutput(); }
-
- /// returns true iff this is a stream parameter
- inline bool forStream() const { return _mIndex.forStream(); }
- /// returns true iff this is a port (input or output) parameter
- inline bool forPort() const { return _mIndex.forPort(); }
-
- /// returns the stream ID or ~0 if not a stream
- inline unsigned stream() const { return _mIndex.stream(); }
-
- /// returns the parameter type: the parameter index without the stream ID
- inline Type type() const { return _mIndex.type(); }
-
- /// returns the index of this parameter
- /// \todo: should we restrict this to C2ParamField?
- inline uint32_t index() const { return (uint32_t)_mIndex; }
-
- /// returns the core index of this parameter
- inline CoreIndex coreIndex() const { return _mIndex.coreIndex(); }
-
- /// returns the kind of this parameter
- inline kind_t kind() const { return _mIndex.kind(); }
-
- /// returns the size of the parameter or 0 if the parameter is invalid
- inline size_t size() const { return _mSize; }
-
- /// returns true iff the parameter is valid
- inline operator bool() const { return _mIndex.isValid() && _mSize > 0; }
-
- /// returns true iff the parameter is invalid
- inline bool operator!() const { return !operator bool(); }
-
- // equality is done by memcmp (use equals() to prevent any overread)
- inline bool operator==(const C2Param &o) const {
- return equals(o) && memcmp(this, &o, _mSize) == 0;
- }
- inline bool operator!=(const C2Param &o) const { return !operator==(o); }
-
- /// safe(r) type cast from pointer and size
- inline static C2Param* From(void *addr, size_t len) {
- // _mSize must fit into size, but really C2Param must also to be a valid param
- if (len < sizeof(C2Param)) {
- return nullptr;
- }
- // _mSize must match length
- C2Param *param = (C2Param*)addr;
- if (param->_mSize != len) {
- return nullptr;
- }
- return param;
- }
-
- /// Returns managed clone of |orig| at heap.
- inline static std::unique_ptr<C2Param> Copy(const C2Param &orig) {
- if (orig.size() == 0) {
- return nullptr;
- }
- void *mem = ::operator new (orig.size());
- C2Param *param = new (mem) C2Param(orig.size(), orig._mIndex);
- param->updateFrom(orig);
- return std::unique_ptr<C2Param>(param);
- }
-
-#if 0
- template<typename P, class=decltype(C2Param(P()))>
- P *As() { return P::From(this); }
- template<typename P>
- const P *As() const { return const_cast<const P*>(P::From(const_cast<C2Param*>(this))); }
-#endif
-
-protected:
- /// sets the stream field. Returns true iff successful.
- inline bool setStream(unsigned stream) {
- return _mIndex.setStream(stream);
- }
-
- /// sets the port (direction). Returns true iff successful.
- inline bool setPort(bool output) {
- return _mIndex.setPort(output);
- }
-
-public:
- /// invalidate this parameter. There is no recovery from this call; e.g. parameter
- /// cannot be 'corrected' to be valid.
- inline void invalidate() { _mSize = 0; }
-
- // if other is the same kind of (valid) param as this, copy it into this and return true.
- // otherwise, do not copy anything, and return false.
- inline bool updateFrom(const C2Param &other) {
- if (other._mSize <= _mSize && other._mIndex == _mIndex && _mSize > 0) {
- memcpy(this, &other, _mSize);
- return true;
- }
- return false;
- }
-
-protected:
- // returns |o| if it is a null ptr, or if can suitably be a param of given |type| (e.g. has
- // same type (ignoring stream ID), and size). Otherwise, returns null. If |checkDir| is false,
- // allow undefined or different direction (e.g. as constructed from C2PortParam() vs.
- // C2PortParam::input), but still require equivalent type (stream, port or global); otherwise,
- // return null.
- inline static const C2Param* IfSuitable(
- const C2Param* o, size_t size, Type type, size_t flexSize = 0, bool checkDir = true) {
- if (o == nullptr || o->_mSize < size || (flexSize && ((o->_mSize - size) % flexSize))) {
- return nullptr;
- } else if (checkDir) {
- return o->_mIndex.type() == type.mIndex ? o : nullptr;
- } else if (o->_mIndex.isGlobal()) {
- return nullptr;
- } else {
- return ((o->_mIndex.type() ^ type.mIndex) & ~Type::DIR_MASK) ? nullptr : o;
- }
- }
-
- /// base constructor
- inline C2Param(uint32_t paramSize, Index paramIndex)
- : _mSize(paramSize),
- _mIndex(paramIndex) {
- if (paramSize > sizeof(C2Param)) {
- memset(this + 1, 0, paramSize - sizeof(C2Param));
- }
- }
-
- /// base constructor with stream set
- inline C2Param(uint32_t paramSize, Index paramIndex, unsigned stream)
- : _mSize(paramSize),
- _mIndex(paramIndex | Index::MakeStreamId(stream)) {
- if (paramSize > sizeof(C2Param)) {
- memset(this + 1, 0, paramSize - sizeof(C2Param));
- }
- if (!forStream()) {
- invalidate();
- }
- }
-
-private:
- friend struct _C2ParamInspector; // for testing
-
- /// returns true iff |o| has the same size and index as this. This performs the
- /// basic check for equality.
- inline bool equals(const C2Param &o) const {
- return _mSize == o._mSize && _mIndex == o._mIndex;
- }
-
- uint32_t _mSize;
- Index _mIndex;
-};
-
-/// \ingroup internal
-/// allow C2Params access to private methods, e.g. constructors
-#define C2PARAM_MAKE_FRIENDS \
- template<typename U, typename S, int I, class F> friend struct C2GlobalParam; \
- template<typename U, typename S, int I, class F> friend struct C2PortParam; \
- template<typename U, typename S, int I, class F> friend struct C2StreamParam; \
-
-/**
- * Setting base structure for component method signatures. Wrap constructors.
- */
-struct C2Setting : public C2Param {
-protected:
- template<typename ...Args>
- inline C2Setting(const Args(&... args)) : C2Param(args...) { }
-public: // TODO
- enum : uint32_t { PARAM_KIND = Type::KIND_SETTING };
-};
-
-/**
- * Tuning base structure for component method signatures. Wrap constructors.
- */
-struct C2Tuning : public C2Setting {
-protected:
- template<typename ...Args>
- inline C2Tuning(const Args(&... args)) : C2Setting(args...) { }
-public: // TODO
- enum : uint32_t { PARAM_KIND = Type::KIND_TUNING };
-};
-
-/**
- * Info base structure for component method signatures. Wrap constructors.
- */
-struct C2Info : public C2Param {
-protected:
- template<typename ...Args>
- inline C2Info(const Args(&... args)) : C2Param(args...) { }
-public: // TODO
- enum : uint32_t { PARAM_KIND = Type::KIND_INFO };
-};
-
-/**
- * Structure uniquely specifying a field in an arbitrary structure.
- *
- * \note This structure is used differently in C2FieldDescriptor to
- * identify array fields, such that _mSize is the size of each element. This is
- * because the field descriptor contains the array-length, and we want to keep
- * a relevant element size for variable length arrays.
- */
-struct _C2FieldId {
-//public:
- /**
- * Constructor used for C2FieldDescriptor that removes the array extent.
- *
- * \param[in] offset pointer to the field in an object at address 0.
- */
- template<typename T, class B=typename std::remove_extent<T>::type>
- inline _C2FieldId(T* offset)
- : // offset is from "0" so will fit on 32-bits
- _mOffset((uint32_t)(uintptr_t)(offset)),
- _mSize(sizeof(B)) { }
-
- /**
- * Direct constructor from offset and size.
- *
- * \param[in] offset offset of the field.
- * \param[in] size size of the field.
- */
- inline _C2FieldId(size_t offset, size_t size)
- : _mOffset(offset), _mSize(size) {}
-
- /**
- * Constructor used to identify a field in an object.
- *
- * \param U[type] pointer to the object that contains this field. This is needed in case the
- * field is in an (inherited) base class, in which case T will be that base class.
- * \param pm[im] member pointer to the field
- */
- template<typename R, typename T, typename U, typename B=typename std::remove_extent<R>::type>
- inline _C2FieldId(U *, R T::* pm)
- : _mOffset((uint32_t)(uintptr_t)(&(((U*)256)->*pm)) - 256u),
- _mSize(sizeof(B)) { }
-
- /**
- * Constructor used to identify a field in an object.
- *
- * \param pm[im] member pointer to the field
- */
- template<typename R, typename T, typename B=typename std::remove_extent<R>::type>
- inline _C2FieldId(R T::* pm)
- : _mOffset((uint32_t)(uintptr_t)(&(((T*)0)->*pm))),
- _mSize(sizeof(B)) { }
-
- inline bool operator==(const _C2FieldId &other) const {
- return _mOffset == other._mOffset && _mSize == other._mSize;
- }
-
- inline bool operator<(const _C2FieldId &other) const {
- return _mOffset < other._mOffset ||
- // NOTE: order parent structure before sub field
- (_mOffset == other._mOffset && _mSize > other._mSize);
- }
-
- DEFINE_OTHER_COMPARISON_OPERATORS(_C2FieldId)
-
-#if 0
- inline uint32_t offset() const { return _mOffset; }
- inline uint32_t size() const { return _mSize; }
-#endif
-
-#if defined(FRIEND_TEST)
- friend void PrintTo(const _C2FieldId &d, ::std::ostream*);
-#endif
-
-private:
- friend struct _C2ParamInspector;
-
- uint32_t _mOffset; // offset of field
- uint32_t _mSize; // size of field
-};
-
-/**
- * Structure uniquely specifying a 'field' in a configuration. The field
- * can be a field of a configuration, a subfield of a field of a configuration,
- * and even the whole configuration. Moreover, if the field can point to an
- * element in a array field, or to the entire array field.
- *
- * This structure is used for querying supported values for a field, as well
- * as communicating configuration failures and conflicts when trying to change
- * a configuration for a component/interface or a store.
- */
-struct C2ParamField {
-//public:
- /**
- * Create a field identifier using a configuration parameter (variable),
- * and a pointer to member.
- *
- * ~~~~~~~~~~~~~ (.cpp)
- *
- * struct C2SomeParam {
- * uint32_t mField;
- * uint32_t mArray[2];
- * C2OtherStruct mStruct;
- * uint32_t mFlexArray[];
- * } *mParam;
- *
- * C2ParamField(mParam, &mParam->mField);
- * C2ParamField(mParam, &mParam->mArray);
- * C2ParamField(mParam, &mParam->mArray[0]);
- * C2ParamField(mParam, &mParam->mStruct.mSubField);
- * C2ParamField(mParam, &mParam->mFlexArray);
- * C2ParamField(mParam, &mParam->mFlexArray[2]);
- *
- * ~~~~~~~~~~~~~
- *
- * \todo fix what this is for T[] (for now size becomes T[1])
- *
- * \param param pointer to parameter
- * \param offset member pointer
- */
- template<typename S, typename T>
- inline C2ParamField(S* param, T* offset)
- : _mIndex(param->index()),
- _mFieldId((T*)((uintptr_t)offset - (uintptr_t)param)) {}
-
- /**
- * Create a field identifier using a configuration parameter (variable),
- * and a member pointer. This method cannot be used to refer to an
- * array element or a subfield.
- *
- * ~~~~~~~~~~~~~ (.cpp)
- *
- * C2SomeParam mParam;
- * C2ParamField(&mParam, &C2SomeParam::mMemberField);
- *
- * ~~~~~~~~~~~~~
- *
- * \param p pointer to parameter
- * \param T member pointer to the field member
- */
- template<typename R, typename T, typename U>
- inline C2ParamField(U *p, R T::* pm) : _mIndex(p->index()), _mFieldId(p, pm) { }
-
- /**
- * Create a field identifier to a configuration parameter (variable).
- *
- * ~~~~~~~~~~~~~ (.cpp)
- *
- * C2SomeParam mParam;
- * C2ParamField(&mParam);
- *
- * ~~~~~~~~~~~~~
- *
- * \param param pointer to parameter
- */
- template<typename S>
- inline C2ParamField(S* param)
- : _mIndex(param->index()), _mFieldId(0u, param->size()) { }
-
- /**
- * Equality operator.
- */
- inline bool operator==(const C2ParamField &other) const {
- return _mIndex == other._mIndex && _mFieldId == other._mFieldId;
- }
-
- /**
- * Ordering operator.
- */
- inline bool operator<(const C2ParamField &other) const {
- return _mIndex < other._mIndex ||
- (_mIndex == other._mIndex && _mFieldId < other._mFieldId);
- }
-
- DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
-
-protected:
- inline C2ParamField(C2Param::Index index, uint32_t offset, uint32_t size)
- : _mIndex(index), _mFieldId(offset, size) {}
-
-private:
- friend struct _C2ParamInspector;
-
- C2Param::Index _mIndex; ///< parameter index
- _C2FieldId _mFieldId; ///< field identifier
-};
-
-/**
- * A shared (union) representation of numeric values
- */
-class C2Value {
-public:
- /// A union of supported primitive types.
- union Primitive {
- // first member is always zero initialized so it must be the largest
- uint64_t u64; ///< uint64_t value
- int64_t i64; ///< int64_t value
- c2_cntr64_t c64; ///< c2_cntr64_t value
- uint32_t u32; ///< uint32_t value
- int32_t i32; ///< int32_t value
- c2_cntr32_t c32; ///< c2_cntr32_t value
- float fp; ///< float value
-
- // constructors - implicit
- Primitive(uint64_t value) : u64(value) { }
- Primitive(int64_t value) : i64(value) { }
- Primitive(c2_cntr64_t value) : c64(value) { }
- Primitive(uint32_t value) : u32(value) { }
- Primitive(int32_t value) : i32(value) { }
- Primitive(c2_cntr32_t value) : c32(value) { }
- Primitive(float value) : fp(value) { }
-
- Primitive() : u64(0) { }
-
- /** gets value out of the union */
- template<typename T> const T &ref() const;
- };
-
- enum type_t : uint32_t {
- NO_INIT,
- INT32,
- UINT32,
- CNTR32,
- INT64,
- UINT64,
- CNTR64,
- FLOAT,
- };
-
- template<typename T> static constexpr type_t typeFor();
-
- // constructors - implicit
- template<typename T>
- C2Value(T value) : _mType(typeFor<T>()), _mValue(value) { }
-
- C2Value() : _mType(NO_INIT) { }
-
- inline type_t type() const { return _mType; }
-
- template<typename T>
- inline bool get(T *value) const {
- if (_mType == typeFor<T>()) {
- *value = _mValue.ref<T>();
- return true;
- }
- return false;
- }
-
-private:
- type_t _mType;
- Primitive _mValue;
-};
-
-template<> inline const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
-template<> inline const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
-template<> inline const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
-template<> inline const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
-template<> inline const c2_cntr32_t &C2Value::Primitive::ref<c2_cntr32_t>() const { return c32; }
-template<> inline const c2_cntr64_t &C2Value::Primitive::ref<c2_cntr64_t>() const { return c64; }
-template<> inline const float &C2Value::Primitive::ref<float>() const { return fp; }
-
-template<> constexpr C2Value::type_t C2Value::typeFor<int32_t>() { return INT32; }
-template<> constexpr C2Value::type_t C2Value::typeFor<int64_t>() { return INT64; }
-template<> constexpr C2Value::type_t C2Value::typeFor<uint32_t>() { return UINT32; }
-template<> constexpr C2Value::type_t C2Value::typeFor<uint64_t>() { return UINT64; }
-template<> constexpr C2Value::type_t C2Value::typeFor<c2_cntr32_t>() { return CNTR32; }
-template<> constexpr C2Value::type_t C2Value::typeFor<c2_cntr64_t>() { return CNTR64; }
-template<> constexpr C2Value::type_t C2Value::typeFor<float>() { return FLOAT; }
-
-/**
- * field descriptor. A field is uniquely defined by an index into a parameter.
- * (Note: Stream-id is not captured as a field.)
- *
- * Ordering of fields is by offset. In case of structures, it is depth first,
- * with a structure taking an index just before and in addition to its members.
- */
-struct C2FieldDescriptor {
-//public:
- /** field types and flags
- * \note: only 32-bit and 64-bit fields are supported (e.g. no boolean, as that
- * is represented using INT32).
- */
- enum type_t : uint32_t {
- // primitive types
- INT32 = C2Value::INT32, ///< 32-bit signed integer
- UINT32 = C2Value::UINT32, ///< 32-bit unsigned integer
- CNTR32 = C2Value::CNTR32, ///< 32-bit counter
- INT64 = C2Value::INT64, ///< 64-bit signed integer
- UINT64 = C2Value::UINT64, ///< 64-bit signed integer
- CNTR64 = C2Value::CNTR64, ///< 64-bit counter
- FLOAT = C2Value::FLOAT, ///< 32-bit floating point
-
- // array types
- STRING = 0x100, ///< fixed-size string (POD)
- BLOB, ///< blob. Blobs have no sub-elements and can be thought of as byte arrays;
- ///< however, bytes cannot be individually addressed by clients.
-
- // complex types
- STRUCT_FLAG = 0x20000, ///< structs. Marked with this flag in addition to their coreIndex.
- };
-
- typedef std::pair<C2String, C2Value::Primitive> NamedValueType;
- typedef std::vector<const NamedValueType> NamedValuesType;
- //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> NamedValuesType;
-
- /**
- * Template specialization that returns the named values for a type.
- *
- * \todo hide from client.
- *
- * \return a vector of name-value pairs.
- */
- template<typename B>
- static NamedValuesType namedValuesFor(const B &);
-
- inline C2FieldDescriptor(uint32_t type, uint32_t extent, C2StringLiteral name, size_t offset, size_t size)
- : _mType((type_t)type), _mExtent(extent), _mName(name), _mFieldId(offset, size) { }
-
- template<typename T, class B=typename std::remove_extent<T>::type>
- inline C2FieldDescriptor(const T* offset, const char *name)
- : _mType(this->GetType((B*)nullptr)),
- _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
- _mName(name),
- _mNamedValues(namedValuesFor(*(B*)0)),
- _mFieldId(offset) {}
-
-/*
- template<typename T, typename B=typename std::remove_extent<T>::type>
- inline C2FieldDescriptor<T, B, false>(T* offset, const char *name)
- : _mType(this->GetType((B*)nullptr)),
- _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
- _mName(name),
- _mFieldId(offset) {}
-*/
-
- /// \deprecated
- template<typename T, typename S, class B=typename std::remove_extent<T>::type>
- constexpr inline C2FieldDescriptor(S*, T S::* field, const char *name)
- : _mType(this->GetType((B*)nullptr)),
- _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
- _mName(name),
- _mFieldId(&(((S*)0)->*field)) {}
-
- /// returns the type of this field
- inline type_t type() const { return _mType; }
- /// returns the length of the field in case it is an array. Returns 0 for
- /// T[] arrays, returns 1 for T[1] arrays as well as if the field is not an array.
- inline size_t extent() const { return _mExtent; }
- /// returns the name of the field
- inline C2StringLiteral name() const { return _mName; }
-
- const NamedValuesType &namedValues() const { return _mNamedValues; }
-
-#if defined(FRIEND_TEST)
- friend void PrintTo(const C2FieldDescriptor &, ::std::ostream*);
- friend bool operator==(const C2FieldDescriptor &, const C2FieldDescriptor &);
- FRIEND_TEST(C2ParamTest_ParamFieldList, VerifyStruct);
-#endif
-
-private:
- type_t _mType;
- uint32_t _mExtent; // the last member can be arbitrary length if it is T[] array,
- // extending to the end of the parameter (this is marked with
- // 0). T[0]-s are not fields.
- C2StringLiteral _mName;
- NamedValuesType _mNamedValues;
-
- _C2FieldId _mFieldId; // field identifier (offset and size)
-
- // NOTE: We do not capture default value(s) here as that may depend on the component.
- // NOTE: We also do not capture bestEffort, as 1) this should be true for most fields,
- // 2) this is at parameter granularity.
-
- // type resolution
- inline static type_t GetType(int32_t*) { return INT32; }
- inline static type_t GetType(uint32_t*) { return UINT32; }
- inline static type_t GetType(c2_cntr32_t*) { return CNTR32; }
- inline static type_t GetType(int64_t*) { return INT64; }
- inline static type_t GetType(uint64_t*) { return UINT64; }
- inline static type_t GetType(c2_cntr64_t*) { return CNTR64; }
- inline static type_t GetType(float*) { return FLOAT; }
- inline static type_t GetType(char*) { return STRING; }
- inline static type_t GetType(uint8_t*) { return BLOB; }
-
- template<typename T,
- class=typename std::enable_if<std::is_enum<T>::value>::type>
- inline static type_t GetType(T*) {
- typename std::underlying_type<T>::type underlying(0);
- return GetType(&underlying);
- }
-
- // verify C2Struct by having a FIELD_LIST and a CORE_INDEX.
- template<typename T,
- class=decltype(T::CORE_INDEX + 1), class=decltype(T::FIELD_LIST)>
- inline static type_t GetType(T*) {
- static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
- return (type_t)(T::CORE_INDEX | STRUCT_FLAG);
- }
-
- friend struct _C2ParamInspector;
-};
-
-#define DEFINE_NO_NAMED_VALUES_FOR(type) \
-template<> inline C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const type &) { \
- return NamedValuesType(); \
-}
-
-// We cannot subtype constructor for enumerated types so insted define no named values for
-// non-enumerated integral types.
-DEFINE_NO_NAMED_VALUES_FOR(int32_t)
-DEFINE_NO_NAMED_VALUES_FOR(uint32_t)
-DEFINE_NO_NAMED_VALUES_FOR(c2_cntr32_t)
-DEFINE_NO_NAMED_VALUES_FOR(int64_t)
-DEFINE_NO_NAMED_VALUES_FOR(uint64_t)
-DEFINE_NO_NAMED_VALUES_FOR(c2_cntr64_t)
-DEFINE_NO_NAMED_VALUES_FOR(uint8_t)
-DEFINE_NO_NAMED_VALUES_FOR(char)
-DEFINE_NO_NAMED_VALUES_FOR(float)
-
-/**
- * Describes the fields of a structure.
- */
-struct C2StructDescriptor {
-public:
- /// Returns the core index of the struct
- inline C2Param::CoreIndex coreIndex() const { return _mType.coreIndex(); }
-
- // Returns the number of fields in this struct (not counting any recursive fields).
- // Must be at least 1 for valid structs.
- inline size_t numFields() const { return _mFields.size(); }
-
- // Returns the list of direct fields (not counting any recursive fields).
- typedef std::vector<const C2FieldDescriptor>::const_iterator field_iterator;
- inline field_iterator cbegin() const { return _mFields.cbegin(); }
- inline field_iterator cend() const { return _mFields.cend(); }
-
- // only supplying const iterator - but these names are needed for range based loops
- inline field_iterator begin() const { return _mFields.cbegin(); }
- inline field_iterator end() const { return _mFields.cend(); }
-
- template<typename T>
- inline C2StructDescriptor(T*)
- : C2StructDescriptor(T::CORE_INDEX, T::FIELD_LIST) { }
-
- inline C2StructDescriptor(
- C2Param::CoreIndex type,
- std::initializer_list<const C2FieldDescriptor> fields)
- : _mType(type), _mFields(fields) { }
-
-private:
- const C2Param::CoreIndex _mType;
- const std::vector<const C2FieldDescriptor> _mFields;
-};
-
-/**
- * Describes parameters for a component.
- */
-struct C2ParamDescriptor {
-public:
- /**
- * Returns whether setting this param is required to configure this component.
- * This can only be true for builtin params for platform-defined components (e.g. video and
- * audio encoders/decoders, video/audio filters).
- * For vendor-defined components, it can be true even for vendor-defined params,
- * but it is not recommended, in case the component becomes platform-defined.
- */
- inline bool isRequired() const { return _mAttrib & IS_REQUIRED; }
-
- /**
- * Returns whether this parameter is persistent. This is always true for C2Tuning and C2Setting,
- * but may be false for C2Info. If true, this parameter persists across frames and applies to
- * the current and subsequent frames. If false, this C2Info parameter only applies to the
- * current frame and is not assumed to have the same value (or even be present) on subsequent
- * frames, unless it is specified for those frames.
- */
- inline bool isPersistent() const { return _mAttrib & IS_PERSISTENT; }
-
- inline bool isStrict() const { return _mAttrib & IS_STRICT; }
-
- inline bool isReadOnly() const { return _mAttrib & IS_READ_ONLY; }
-
- inline bool isVisible() const { return !(_mAttrib & IS_HIDDEN); }
-
- inline bool isPublic() const { return !(_mAttrib & IS_INTERNAL); }
-
- /// Returns the name of this param.
- /// This defaults to the underlying C2Struct's name, but could be altered for a component.
- inline C2String name() const { return _mName; }
-
- /// Returns the parameter index
- inline C2Param::Index index() const { return _mIndex; }
-
- /// Returns the indices of parameters that this parameter has a dependency on
- inline const std::vector<C2Param::Index> &dependencies() const { return _mDependencies; }
-
- /// \deprecated
- template<typename T>
- inline C2ParamDescriptor(bool isRequired, C2StringLiteral name, const T*)
- : _mIndex(T::PARAM_TYPE),
- _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
- _mName(name) { }
-
- /// \deprecated
- inline C2ParamDescriptor(
- bool isRequired, C2StringLiteral name, C2Param::Index index)
- : _mIndex(index),
- _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
- _mName(name) { }
-
- enum attrib_t : uint32_t {
- // flags that default on
- IS_REQUIRED = 1u << 0, ///< parameter is required to be specified
- IS_PERSISTENT = 1u << 1, ///< parameter retains its value
- // flags that default off
- IS_STRICT = 1u << 2, ///< parameter is strict
- IS_READ_ONLY = 1u << 3, ///< parameter is publicly read-only
- IS_HIDDEN = 1u << 4, ///< parameter shall not be visible to clients
- IS_INTERNAL = 1u << 5, ///< parameter shall not be used by framework (other than testing)
- };
-
- inline C2ParamDescriptor(
- C2Param::Index index, attrib_t attrib, C2StringLiteral name)
- : _mIndex(index),
- _mAttrib(attrib),
- _mName(name) { }
-
- inline C2ParamDescriptor(
- C2Param::Index index, attrib_t attrib, C2String &&name,
- std::vector<C2Param::Index> &&dependencies)
- : _mIndex(index),
- _mAttrib(attrib),
- _mName(name),
- _mDependencies(std::move(dependencies)) { }
-
-private:
- const C2Param::Index _mIndex;
- const uint32_t _mAttrib;
- const C2String _mName;
- std::vector<C2Param::Index> _mDependencies;
-
- friend struct _C2ParamInspector;
-};
-
-/// \ingroup internal
-/// Define a structure without CORE_INDEX.
-#define DEFINE_BASE_C2STRUCT(name) \
-public: \
- typedef C2##name##Struct _type; /**< type name shorthand */ \
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST; /**< structure fields */
-
-/// Define a structure with matching CORE_INDEX.
-#define DEFINE_C2STRUCT(name) \
-public: \
- enum : uint32_t { CORE_INDEX = kParamIndex##name }; \
- DEFINE_BASE_C2STRUCT(name)
-
-/// Define a flexible structure without CORE_INDEX.
-#define DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) \
-public: \
- FLEX(C2##name##Struct, flexMember) \
- DEFINE_BASE_C2STRUCT(name)
-
-/// Define a flexible structure with matching CORE_INDEX.
-#define DEFINE_FLEX_C2STRUCT(name, flexMember) \
-public: \
- FLEX(C2##name##Struct, flexMember) \
- enum : uint32_t { CORE_INDEX = kParamIndex##name | C2Param::CoreIndex::IS_FLEX_FLAG }; \
- DEFINE_BASE_C2STRUCT(name)
-
-#ifdef __C2_GENERATE_GLOBAL_VARS__
-/// \ingroup internal
-/// Describe a structure of a templated structure.
-#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list) \
- template<> \
- const std::initializer_list<const C2FieldDescriptor> strukt::FIELD_LIST = list;
-
-/// \deprecated
-/// Describe the fields of a structure using an initializer list.
-#define DESCRIBE_C2STRUCT(name, list) \
- const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::FIELD_LIST = list;
-#else
-/// \if 0
-#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list)
-#define DESCRIBE_C2STRUCT(name, list)
-/// \endif
-#endif
-
-/**
- * Describe a field of a structure.
- * These must be in order.
- *
- * There are two ways to use this macro:
- *
- * ~~~~~~~~~~~~~ (.cpp)
- * struct C2VideoWidthStruct {
- * int32_t width;
- * C2VideoWidthStruct() {} // optional default constructor
- * C2VideoWidthStruct(int32_t _width) : width(_width) {}
- *
- * DEFINE_AND_DESCRIBE_C2STRUCT(VideoWidth)
- * C2FIELD(width, "width")
- * };
- * ~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~ (.cpp)
- * struct C2VideoWidthStruct {
- * int32_t width;
- * C2VideoWidthStruct() = default; // optional default constructor
- * C2VideoWidthStruct(int32_t _width) : width(_width) {}
- *
- * DEFINE_C2STRUCT(VideoWidth)
- * } C2_PACK;
- *
- * DESCRIBE_C2STRUCT(VideoWidth, {
- * C2FIELD(width, "width")
- * })
- * ~~~~~~~~~~~~~
- *
- * For flexible structures (those ending in T[]), use the flexible macros:
- *
- * ~~~~~~~~~~~~~ (.cpp)
- * struct C2VideoFlexWidthsStruct {
- * int32_t widths[];
- * C2VideoFlexWidthsStruct(); // must have a default constructor
- *
- * private:
- * // may have private constructors taking number of widths as the first argument
- * // This is used by the C2Param factory methods, e.g.
- * // C2VideoFlexWidthsGlobalParam::AllocUnique(size_t, int32_t);
- * C2VideoFlexWidthsStruct(size_t flexCount, int32_t value) {
- * for (size_t i = 0; i < flexCount; ++i) {
- * widths[i] = value;
- * }
- * }
- *
- * // If the last argument is T[N] or std::initializer_list<T>, the flexCount will
- * // be automatically calculated and passed by the C2Param factory methods, e.g.
- * // int widths[] = { 1, 2, 3 };
- * // C2VideoFlexWidthsGlobalParam::AllocUnique(widths);
- * template<unsigned N>
- * C2VideoFlexWidthsStruct(size_t flexCount, const int32_t(&init)[N]) {
- * for (size_t i = 0; i < flexCount; ++i) {
- * widths[i] = init[i];
- * }
- * }
- *
- * DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoFlexWidths, widths)
- * C2FIELD(widths, "widths")
- * };
- * ~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~ (.cpp)
- * struct C2VideoFlexWidthsStruct {
- * int32_t mWidths[];
- * C2VideoFlexWidthsStruct(); // must have a default constructor
- *
- * DEFINE_FLEX_C2STRUCT(VideoFlexWidths, mWidths)
- * } C2_PACK;
- *
- * DESCRIBE_C2STRUCT(VideoFlexWidths, {
- * C2FIELD(mWidths, "widths")
- * })
- * ~~~~~~~~~~~~~
- *
- */
-#ifdef __C2_GENERATE_GLOBAL_VARS__
-#define C2FIELD(member, name) \
- C2FieldDescriptor(&((_type*)(nullptr))->member, name),
-
-/// \deprecated
-#define C2SOLE_FIELD(member, name) \
- C2FieldDescriptor(&_type::member, name, 0)
-
-/// Define a structure with matching CORE_INDEX and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
- DEFINE_C2STRUCT(name) } C2_PACK; \
- const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::FIELD_LIST = {
-
-/// Define a flexible structure with matching CORE_INDEX and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
- DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
- const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::FIELD_LIST = {
-
-/// Define a base structure (with no CORE_INDEX) and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
- DEFINE_BASE_C2STRUCT(name) } C2_PACK; \
- const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::FIELD_LIST = {
-
-/// Define a flexible base structure (with no CORE_INDEX) and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
- DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
- const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::FIELD_LIST = {
-
-#else
-/// \if 0
-/* Alternate declaration of field definitions in case no field list is to be generated.
- TRICKY: use namespace declaration to handle closing bracket that is normally after
- these macros. */
-#define C2FIELD(member, name)
-/// \deprecated
-#define C2SOLE_FIELD(member, name)
-/// Define a structure with matching CORE_INDEX and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
- DEFINE_C2STRUCT(name) } C2_PACK; namespace ignored {
-/// Define a flexible structure with matching CORE_INDEX and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
- DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
-/// Define a base structure (with no CORE_INDEX) and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
- DEFINE_BASE_C2STRUCT(name) } C2_PACK; namespace ignored {
-/// Define a flexible base structure (with no CORE_INDEX) and start describing its fields.
-/// This must be at the end of the structure definition.
-#define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
- DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
-/// \endif
-#endif
-
-/**
- * Parameter reflector class.
- *
- * This class centralizes the description of parameter structures. This can be shared
- * by multiple components as describing a parameter does not imply support of that
- * parameter. However, each supported parameter and any dependent structures within
- * must be described by the parameter reflector provided by a component.
- */
-class C2ParamReflector {
-public:
- /**
- * Describes a parameter structure.
- *
- * \param[in] coreIndex the core index of the parameter structure containing at least the
- * core index
- *
- * \return the description of the parameter structure
- * \retval nullptr if the parameter is not supported by this reflector
- *
- * This methods shall not block and return immediately.
- *
- * \note this class does not take a set of indices because we would then prefer
- * to also return any dependent structures, and we don't want this logic to be
- * repeated in each reflector. Alternately, this could just return a map of all
- * descriptions, but we want to conserve memory if client only wants the description
- * of a few indices.
- */
- virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const = 0;
-
-protected:
- virtual ~C2ParamReflector() = default;
-};
-
-/**
- * Generic supported values for a field.
- *
- * This can be either a range or a set of values. The range can be a simple range, an arithmetic,
- * geometric or multiply-accumulate series with a clear minimum and maximum value. Values can
- * be discrete values, or can optionally represent flags to be or-ed.
- *
- * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
- */
-struct C2FieldSupportedValues {
-//public:
- enum type_t {
- EMPTY, ///< no supported values
- RANGE, ///< a numeric range that can be continuous or discrete
- VALUES, ///< a list of values
- FLAGS ///< a list of flags that can be OR-ed
- };
-
- type_t type; /** Type of values for this field. */
-
- typedef C2Value::Primitive Primitive;
-
- /**
- * Range specifier for supported value. Used if type is RANGE.
- *
- * If step is 0 and num and denom are both 1, the supported values are any value, for which
- * min <= value <= max.
- *
- * Otherwise, the range represents a geometric/arithmetic/multiply-accumulate series, where
- * successive supported values can be derived from previous values (starting at min), using the
- * following formula:
- * v[0] = min
- * v[i] = v[i-1] * num / denom + step for i >= 1, while min < v[i] <= max.
- */
- struct {
- /** Lower end of the range (inclusive). */
- Primitive min;
- /** Upper end of the range (inclusive if permitted by series). */
- Primitive max;
- /** Step between supported values. */
- Primitive step;
- /** Numerator of a geometric series. */
- Primitive num;
- /** Denominator of a geometric series. */
- Primitive denom;
- } range;
-
- /**
- * List of values. Used if type is VALUES or FLAGS.
- *
- * If type is VALUES, this is the list of supported values in decreasing preference.
- *
- * If type is FLAGS, this vector contains { min-mask, flag1, flag2... }. Basically, the first
- * value is the required set of flags to be set, and the rest of the values are flags that can
- * be set independently. FLAGS is only supported for integral types. Supported flags should
- * not overlap, as it can make validation non-deterministic. The standard validation method
- * is that starting from the original value, if each flag is removed when fully present (the
- * min-mask must be fully present), we shall arrive at 0.
- */
- std::vector<Primitive> values;
-
- C2FieldSupportedValues()
- : type(EMPTY) {
- }
-
- template<typename T>
- C2FieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
- : type(RANGE),
- range{min, max, step, (T)1, (T)1} { }
-
- template<typename T>
- C2FieldSupportedValues(T min, T max, T num, T den) :
- type(RANGE),
- range{min, max, (T)0, num, den} { }
-
- template<typename T>
- C2FieldSupportedValues(T min, T max, T step, T num, T den)
- : type(RANGE),
- range{min, max, step, num, den} { }
-
- /// \deprecated
- template<typename T>
- C2FieldSupportedValues(bool flags, std::initializer_list<T> list)
- : type(flags ? FLAGS : VALUES),
- range{(T)0, (T)0, (T)0, (T)0, (T)0} {
- for (T value : list) {
- values.emplace_back(value);
- }
- }
-
- /// \deprecated
- template<typename T>
- C2FieldSupportedValues(bool flags, const std::vector<T>& list)
- : type(flags ? FLAGS : VALUES),
- range{(T)0, (T)0, (T)0, (T)0, (T)0} {
- for(T value : list) {
- values.emplace_back(value);
- }
- }
-
- /// \internal
- /// \todo: create separate values vs. flags initializer as for flags we want
- /// to list both allowed and required flags
- template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
- C2FieldSupportedValues(bool flags, const T*)
- : type(flags ? FLAGS : VALUES),
- range{(T)0, (T)0, (T)0, (T)0, (T)0} {
- C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)0);
- if (flags) {
- values.emplace_back(0); // min-mask defaults to 0
- }
- for (const C2FieldDescriptor::NamedValueType &item : named){
- values.emplace_back(item.second);
- }
- }
-};
-
-/**
- * Supported values for a specific field.
- *
- * This is a pair of the field specifier together with an optional supported values object.
- * This structure is used when reporting parameter configuration failures and conflicts.
- */
-struct C2ParamFieldValues {
- C2ParamField paramOrField; ///< the field or parameter
- /// optional supported values for the field if paramOrField specifies an actual field that is
- /// numeric (non struct, blob or string). Supported values for arrays (including string and
- /// blobs) describe the supported values for each element (character for string, and bytes for
- /// blobs). It is optional for read-only strings and blobs.
- std::unique_ptr<C2FieldSupportedValues> values;
-
- // This struct is meant to be move constructed.
- C2_DEFAULT_MOVE(C2ParamFieldValues);
-
- // Copy constructor/assignment is also provided as this object may get copied.
- C2ParamFieldValues(const C2ParamFieldValues &other)
- : paramOrField(other.paramOrField),
- values(other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr) { }
-
- C2ParamFieldValues& operator=(const C2ParamFieldValues &other) {
- paramOrField = other.paramOrField;
- values = other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr;
- return *this;
- }
-
-
- /**
- * Construct with no values.
- */
- C2ParamFieldValues(const C2ParamField ¶mOrField_)
- : paramOrField(paramOrField_) { }
-
- /**
- * Construct with values.
- */
- C2ParamFieldValues(const C2ParamField ¶mOrField_, const C2FieldSupportedValues &values_)
- : paramOrField(paramOrField_),
- values(std::make_unique<C2FieldSupportedValues>(values_)) { }
-
- /**
- * Construct from fields.
- */
- C2ParamFieldValues(const C2ParamField ¶mOrField_, std::unique_ptr<C2FieldSupportedValues> &&values_)
- : paramOrField(paramOrField_),
- values(std::move(values_)) { }
-};
-
-/// @}
-
-#endif // C2PARAM_H_
diff --git a/media/libstagefright/codec2/include/C2ParamDef.h b/media/libstagefright/codec2/include/C2ParamDef.h
deleted file mode 100644
index 86c6833..0000000
--- a/media/libstagefright/codec2/include/C2ParamDef.h
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-/** \file
- * Templates used to declare parameters.
- */
-#ifndef C2PARAM_DEF_H_
-#define C2PARAM_DEF_H_
-
-#include <type_traits>
-
-#include <C2Param.h>
-
-/// \addtogroup Parameters
-/// @{
-
-/* ======================== UTILITY TEMPLATES FOR PARAMETER DEFINITIONS ======================== */
-
-/// \addtogroup internal
-/// @{
-
-/// Helper class that checks if a type has equality and inequality operators.
-struct C2_HIDE _C2Comparable_impl
-{
- template<typename S, typename=decltype(S() == S())>
- static std::true_type TestEqual(int);
- template<typename>
- static std::false_type TestEqual(...);
-
- template<typename S, typename=decltype(S() != S())>
- static std::true_type TestNotEqual(int);
- template<typename>
- static std::false_type TestNotEqual(...);
-};
-
-/**
- * Helper template that returns if a type has equality and inequality operators.
- *
- * Use as _C2Comparable<typename S>::value.
- */
-template<typename S>
-struct C2_HIDE _C2Comparable
- : public std::integral_constant<bool, decltype(_C2Comparable_impl::TestEqual<S>(0))::value
- || decltype(_C2Comparable_impl::TestNotEqual<S>(0))::value> {
-};
-
-/// Helper class that checks if a type has a CORE_INDEX constant.
-struct C2_HIDE _C2CoreIndexHelper_impl
-{
- template<typename S, int=S::CORE_INDEX>
- static std::true_type TestCoreIndex(int);
- template<typename>
- static std::false_type TestCoreIndex(...);
-};
-
-/// Helper template that verifies a type's CORE_INDEX and creates it if the type does not have one.
-template<typename S, int CoreIndex,
- bool HasBase=decltype(_C2CoreIndexHelper_impl::TestCoreIndex<S>(0))::value>
-struct C2_HIDE _C2CoreIndexOverride {
- // TODO: what if we allow structs without CORE_INDEX?
- static_assert(CoreIndex == S::CORE_INDEX, "CORE_INDEX differs from structure");
-};
-
-/// Specialization for types without a CORE_INDEX.
-template<typename S, int CoreIndex>
-struct C2_HIDE _C2CoreIndexOverride<S, CoreIndex, false> {
-public:
- enum : uint32_t {
- CORE_INDEX = CoreIndex, ///< CORE_INDEX override.
- };
-};
-
-/// Helper template that adds a CORE_INDEX to a type if it does not have one.
-template<typename S, int CoreIndex>
-struct C2_HIDE _C2AddCoreIndex : public S, public _C2CoreIndexOverride<S, CoreIndex> {};
-
-/**
- * \brief Helper class to check struct requirements for parameters.
- *
- * Features:
- * - verify default constructor, no virtual methods, and no equality operators.
- * - expose PARAM_TYPE, and non-flex FLEX_SIZE.
- */
-template<typename S, int CoreIndex, unsigned TypeFlags>
-struct C2_HIDE _C2StructCheck {
- static_assert(
- std::is_default_constructible<S>::value, "C2 structure must have default constructor");
- static_assert(!std::is_polymorphic<S>::value, "C2 structure must not have virtual methods");
- static_assert(!_C2Comparable<S>::value, "C2 structure must not have operator== or !=");
-
-public:
- enum : uint32_t {
- PARAM_TYPE = CoreIndex | TypeFlags
- };
-
-protected:
- enum : uint32_t {
- FLEX_SIZE = 0, // TODO: is this still needed? this may be confusing.
- };
-};
-
-/// Helper class that checks if a type has an integer FLEX_SIZE member.
-struct C2_HIDE _C2Flexible_impl {
- /// specialization for types that have a FLEX_SIZE member
- template<typename S, unsigned=S::FLEX_SIZE>
- static std::true_type TestFlexSize(int);
- template<typename>
- static std::false_type TestFlexSize(...);
-};
-
-/// Helper template that returns if a type has an integer FLEX_SIZE member.
-template<typename S>
-struct C2_HIDE _C2Flexible
- : public std::integral_constant<bool, decltype(_C2Flexible_impl::TestFlexSize<S>(0))::value> {
-};
-
-/// Macro to test if a type is flexible (has a FLEX_SIZE member).
-#define IF_FLEXIBLE(S) ENABLE_IF(_C2Flexible<S>::value)
-/// Shorthand for std::enable_if
-#define ENABLE_IF(cond) typename std::enable_if<cond>::type
-
-/// Helper template that exposes the flexible subtype of a struct.
-template<typename S, typename E=void>
-struct C2_HIDE _C2FlexHelper {
- typedef void FlexType;
- enum : uint32_t { FLEX_SIZE = 0 };
-};
-
-/// Specialization for flexible types.
-template<typename S>
-struct C2_HIDE _C2FlexHelper<S,
- typename std::enable_if<!std::is_void<typename S::flexMemberType>::value>::type> {
- typedef typename _C2FlexHelper<typename S::flexMemberType>::FlexType FlexType;
- enum : uint32_t { FLEX_SIZE = _C2FlexHelper<typename S::flexMemberType>::FLEX_SIZE };
-};
-
-/// Specialization for flex arrays.
-template<typename S>
-struct C2_HIDE _C2FlexHelper<S[],
- typename std::enable_if<std::is_void<typename _C2FlexHelper<S>::FlexType>::value>::type> {
- typedef S FlexType;
- enum : uint32_t { FLEX_SIZE = sizeof(S) };
-};
-
-/**
- * \brief Helper class to check flexible struct requirements and add common operations.
- *
- * Features:
- * - expose CORE_INDEX and FIELD_LIST (this is normally inherited from the struct, but flexible
- * structs cannot be base classes and thus inherited from)
- * - disable copy assignment and construction (TODO: this is already done in the FLEX macro for the
- * flexible struct, so may not be needed here)
- */
-template<typename S, int ParamIndex, unsigned TypeFlags>
-struct C2_HIDE _C2FlexStructCheck :
-// add flexible flag as _C2StructCheck defines PARAM_TYPE
- public _C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
-public:
- enum : uint32_t {
- /// \hideinitializer
- CORE_INDEX = ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, ///< flexible struct core-index
- };
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST; // TODO assign here
-
- // default constructor needed because of the disabled copy constructor
- inline _C2FlexStructCheck() = default;
-
-protected:
- // cannot copy flexible params
- _C2FlexStructCheck(const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
- _C2FlexStructCheck& operator= (const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
-
- // constants used for helper methods
- enum : uint32_t {
- /// \hideinitializer
- FLEX_SIZE = _C2FlexHelper<S>::FLEX_SIZE, ///< size of flexible type
- /// \hideinitializer
- MAX_SIZE = (uint32_t)std::min((size_t)UINT32_MAX, SIZE_MAX), // TODO: is this always u32 max?
- /// \hideinitializer
- BASE_SIZE = sizeof(S) + sizeof(C2Param), ///< size of the base param
- };
-
- /// returns the allocated size of this param with flexCount, or 0 if it would overflow.
- inline static size_t CalcSize(size_t flexCount, size_t size = BASE_SIZE) {
- if (flexCount <= (MAX_SIZE - size) / S::FLEX_SIZE) {
- return size + S::FLEX_SIZE * flexCount;
- }
- return 0;
- }
-
- /// dynamic new operator usable for params of type S
- inline void* operator new(size_t size, size_t flexCount) noexcept {
- // TODO: assert(size == BASE_SIZE);
- size = CalcSize(flexCount, size);
- if (size > 0) {
- return ::operator new(size);
- }
- return nullptr;
- }
-};
-
-// TODO: this probably does not work.
-/// Expose FIELD_LIST from subClass;
-template<typename S, int ParamIndex, unsigned TypeFlags>
-const std::initializer_list<const C2FieldDescriptor>
-_C2FlexStructCheck<S, ParamIndex, TypeFlags>::FIELD_LIST = S::FIELD_LIST;
-
-/// Define From() cast operators for params.
-#define DEFINE_CAST_OPERATORS(_Type) \
- inline static _Type* From(C2Param *other) { \
- return (_Type*)C2Param::IfSuitable( \
- other, sizeof(_Type), _Type::PARAM_TYPE, _Type::FLEX_SIZE, \
- (_Type::PARAM_TYPE & T::Index::DIR_UNDEFINED) != T::Index::DIR_UNDEFINED); \
- } \
- inline static const _Type* From(const C2Param *other) { \
- return const_cast<const _Type*>(From(const_cast<C2Param *>(other))); \
- } \
- inline static _Type* From(std::nullptr_t) { return nullptr; } \
-
-/**
- * Define flexible allocators (AllocShared or AllocUnique) for flexible params.
- * - P::AllocXyz(flexCount, args...): allocate for given flex-count.
- * - P::AllocXyz(args..., T[]): allocate for size of (and with) init array.
- * - P::AllocXyz(T[]): allocate for size of (and with) init array with no other args.
- * - P::AllocXyz(args..., std::initializer_list<T>): allocate for size of (and with) initializer
- * list.
- */
-#define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr, Ptr) \
- template<typename ...Args> \
- inline static std::ptr##_ptr<_Type> Alloc##Ptr(size_t flexCount, const Args(&... args)) { \
- return std::ptr##_ptr<_Type>(new(flexCount) _Type(flexCount, args...)); \
- } \
- /* NOTE: unfortunately this is not supported by clang yet */ \
- template<typename ...Args, typename U=typename S::FlexType, unsigned N> \
- inline static std::ptr##_ptr<_Type> Alloc##Ptr(const Args(&... args), const U(&init)[N]) { \
- return std::ptr##_ptr<_Type>(new(N) _Type(N, args..., init)); \
- } \
- /* so for now, specialize for no args */ \
- template<typename U=typename S::FlexType, unsigned N> \
- inline static std::ptr##_ptr<_Type> Alloc##Ptr(const U(&init)[N]) { \
- return std::ptr##_ptr<_Type>(new(N) _Type(N, init)); \
- } \
- template<typename ...Args, typename U=typename S::FlexType> \
- inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
- const Args(&... args), const std::initializer_list<U> &init) { \
- return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
- } \
-
-/**
- * Define flexible methods AllocShared, AllocUnique and flexCount.
- */
-#define DEFINE_FLEXIBLE_METHODS(_Type, S) \
- DEFINE_FLEXIBLE_ALLOC(_Type, S, shared, Shared) \
- DEFINE_FLEXIBLE_ALLOC(_Type, S, unique, Unique) \
- inline size_t flexCount() const { \
- static_assert(sizeof(_Type) == _Type::BASE_SIZE, "incorrect BASE_SIZE"); \
- size_t sz = this->size(); \
- if (sz >= sizeof(_Type)) { \
- return (sz - sizeof(_Type)) / _Type::FLEX_SIZE; \
- } \
- return 0; \
- } \
-
-/// Mark flexible member variable and make structure flexible.
-#define FLEX(cls, m) \
- C2_DO_NOT_COPY(cls) \
-private: \
- C2PARAM_MAKE_FRIENDS \
- /* default constructor with flexCount */ \
- inline cls(size_t) : cls() {} \
- /** \if 0 */ \
- template<typename, typename> friend struct _C2FlexHelper; \
- typedef decltype(m) flexMemberType; \
-public: \
- /* constexpr static flexMemberType cls::* flexMember = &cls::m; */ \
- typedef typename _C2FlexHelper<flexMemberType>::FlexType FlexType; \
- static_assert(\
- !std::is_void<FlexType>::value, \
- "member is not flexible, or a flexible array of a flexible type"); \
- enum : uint32_t { FLEX_SIZE = _C2FlexHelper<flexMemberType>::FLEX_SIZE }; \
- /** \endif */ \
-
-/// @}
-
-/**
- * Global-parameter template.
- *
- * Base template to define a global setting/tuning or info based on a structure and
- * an optional ParamIndex. Global parameters are not tied to a port (input or output).
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
- * structure can be accessed directly, and constructors and potential public methods are also
- * wrapped.
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped structure
- * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
- * structures.
- */
-template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2GlobalParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
-private:
- typedef C2GlobalParam<T, S, ParamIndex> _Type;
-
-public:
- /// Wrapper around base structure's constructor.
- template<typename ...Args>
- inline C2GlobalParam(const Args(&... args)) : T(sizeof(_Type), _Type::PARAM_TYPE), S(args...) { }
-
- DEFINE_CAST_OPERATORS(_Type)
-};
-
-/**
- * Global-parameter template for flexible structures.
- *
- * Base template to define a global setting/tuning or info based on a flexible structure and
- * an optional ParamIndex. Global parameters are not tied to a port (input or output).
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped flexible structure
- * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
- * structures.
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
- * structures can be accessed via the m member variable; however, the constructors of the structure
- * are wrapped directly. (This is because flexible types cannot be subclassed.)
- */
-template<typename T, typename S, int ParamIndex>
-struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
- : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
-private:
- typedef C2GlobalParam<T, S, ParamIndex> _Type;
-
- /// Wrapper around base structure's constructor.
- template<typename ...Args>
- inline C2GlobalParam(size_t flexCount, const Args(&... args))
- : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
-
-public:
- S m; ///< wrapped flexible structure
-
- DEFINE_FLEXIBLE_METHODS(_Type, S)
- DEFINE_CAST_OPERATORS(_Type)
-};
-
-/**
- * Port-parameter template.
- *
- * Base template to define a port setting/tuning or info based on a structure and
- * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
- * specific stream.
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped structure
- * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
- * structures.
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
- * structure can be accessed directly, and constructors and potential public methods are also
- * wrapped.
- *
- * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
- * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
- */
-template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2PortParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- private _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
-private:
- typedef C2PortParam<T, S, ParamIndex> _Type;
-
-public:
- /// Default constructor.
- inline C2PortParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
- template<typename ...Args>
- /// Wrapper around base structure's constructor while specifying port/direction.
- inline C2PortParam(bool _output, const Args(&... args))
- : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE), S(args...) { }
- /// Set port/direction.
- inline void setPort(bool output) { C2Param::setPort(output); }
-
- DEFINE_CAST_OPERATORS(_Type)
-
- /// Specialization for an input port parameter.
- struct input : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
- /// Wrapper around base structure's constructor.
- template<typename ...Args>
- inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
-
- DEFINE_CAST_OPERATORS(input)
-
- };
-
- /// Specialization for an output port parameter.
- struct output : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
- /// Wrapper around base structure's constructor.
- template<typename ...Args>
- inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
-
- DEFINE_CAST_OPERATORS(output)
- };
-};
-
-/**
- * Port-parameter template for flexible structures.
- *
- * Base template to define a port setting/tuning or info based on a flexible structure and
- * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
- * specific stream.
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped flexible structure
- * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
- * structures.
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
- * structures can be accessed via the m member variable; however, the constructors of the structure
- * are wrapped directly. (This is because flexible types cannot be subclassed.)
- *
- * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
- * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
- */
-template<typename T, typename S, int ParamIndex>
-struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
- : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
-private:
- typedef C2PortParam<T, S, ParamIndex> _Type;
-
- /// Default constructor for basic allocation: new(flexCount) P.
- inline C2PortParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE) { }
- template<typename ...Args>
- /// Wrapper around base structure's constructor while also specifying port/direction.
- inline C2PortParam(size_t flexCount, bool _output, const Args(&... args))
- : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
- m(flexCount, args...) { }
-
-public:
- /// Set port/direction.
- inline void setPort(bool output) { C2Param::setPort(output); }
-
- S m; ///< wrapped flexible structure
-
- DEFINE_FLEXIBLE_METHODS(_Type, S)
- DEFINE_CAST_OPERATORS(_Type)
-
- /// Specialization for an input port parameter.
- struct input : public T,
- public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
- private:
- /// Wrapper around base structure's constructor while also specifying port/direction.
- template<typename ...Args>
- inline input(size_t flexCount, const Args(&... args))
- : T(_Type::CalcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
-
- public:
- S m; ///< wrapped flexible structure
-
- DEFINE_FLEXIBLE_METHODS(input, S)
- DEFINE_CAST_OPERATORS(input)
- };
-
- /// Specialization for an output port parameter.
- struct output : public T,
- public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
- private:
- /// Wrapper around base structure's constructor while also specifying port/direction.
- template<typename ...Args>
- inline output(size_t flexCount, const Args(&... args))
- : T(_Type::CalcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
-
- public:
- S m; ///< wrapped flexible structure
-
- DEFINE_FLEXIBLE_METHODS(output, S)
- DEFINE_CAST_OPERATORS(output)
- };
-};
-
-/**
- * Stream-parameter template.
- *
- * Base template to define a stream setting/tuning or info based on a structure and
- * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
- * output).
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped structure
- * \tparam ParamIndex optional paramter index override. Must be specified for base/reused
- * structures.
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
- * structure can be accessed directly, and constructors and potential public methods are also
- * wrapped.
- *
- * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
- * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
- * parameters with unspecified port expose a setPort method, and add an additional initial port
- * parameter to the constructor.
- */
-template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2StreamParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- private _C2StructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
-private:
- typedef C2StreamParam<T, S, ParamIndex> _Type;
-
-public:
- /// Default constructor. Port/direction and stream-ID is undefined.
- inline C2StreamParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
- /// Wrapper around base structure's constructor while also specifying port/direction and
- /// stream-ID.
- template<typename ...Args>
- inline C2StreamParam(bool _output, unsigned stream, const Args(&... args))
- : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
- S(args...) { }
- /// Set port/direction.
- inline void setPort(bool output) { C2Param::setPort(output); }
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_CAST_OPERATORS(_Type)
-
- /// Specialization for an input stream parameter.
- struct input : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- public _C2StructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
- /// Default constructor. Stream-ID is undefined.
- inline input() : T(sizeof(_Type), input::PARAM_TYPE) { }
- /// Wrapper around base structure's constructor while also specifying stream-ID.
- template<typename ...Args>
- inline input(unsigned stream, const Args(&... args))
- : T(sizeof(_Type), input::PARAM_TYPE, stream), S(args...) { }
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_CAST_OPERATORS(input)
- };
-
- /// Specialization for an output stream parameter.
- struct output : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
- public _C2StructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
- /// Default constructor. Stream-ID is undefined.
- inline output() : T(sizeof(_Type), output::PARAM_TYPE) { }
- /// Wrapper around base structure's constructor while also specifying stream-ID.
- template<typename ...Args>
- inline output(unsigned stream, const Args(&... args))
- : T(sizeof(_Type), output::PARAM_TYPE, stream), S(args...) { }
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_CAST_OPERATORS(output)
- };
-};
-
-/**
- * Stream-parameter template for flexible structures.
- *
- * Base template to define a stream setting/tuning or info based on a flexible structure and
- * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
- * output).
- *
- * \tparam T param type C2Setting, C2Tuning or C2Info
- * \tparam S wrapped flexible structure
- * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
- * structures.
- *
- * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
- * structures can be accessed via the m member variable; however, the constructors of the structure
- * are wrapped directly. (This is because flexible types cannot be subclassed.)
- *
- * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
- * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
- * parameters with unspecified port expose a setPort method, and add an additional initial port
- * parameter to the constructor.
- */
-template<typename T, typename S, int ParamIndex>
-struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
- : public T,
- public _C2FlexStructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
-private:
- typedef C2StreamParam<T, S, ParamIndex> _Type;
- /// Default constructor. Port/direction and stream-ID is undefined.
- inline C2StreamParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
- /// Wrapper around base structure's constructor while also specifying port/direction and
- /// stream-ID.
- template<typename ...Args>
- inline C2StreamParam(size_t flexCount, bool _output, unsigned stream, const Args(&... args))
- : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
- m(flexCount, args...) { }
-
-public:
- S m; ///< wrapped flexible structure
-
- /// Set port/direction.
- inline void setPort(bool output) { C2Param::setPort(output); }
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_FLEXIBLE_METHODS(_Type, S)
- DEFINE_CAST_OPERATORS(_Type)
-
- /// Specialization for an input stream parameter.
- struct input : public T,
- public _C2FlexStructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
- private:
- /// Default constructor. Stream-ID is undefined.
- inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
- /// Wrapper around base structure's constructor while also specifying stream-ID.
- template<typename ...Args>
- inline input(size_t flexCount, unsigned stream, const Args(&... args))
- : T(_Type::CalcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
-
- public:
- S m; ///< wrapped flexible structure
-
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_FLEXIBLE_METHODS(input, S)
- DEFINE_CAST_OPERATORS(input)
- };
-
- /// Specialization for an output stream parameter.
- struct output : public T,
- public _C2FlexStructCheck<S, ParamIndex,
- T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
- private:
- /// Default constructor. Stream-ID is undefined.
- inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
- /// Wrapper around base structure's constructor while also specifying stream-ID.
- template<typename ...Args>
- inline output(size_t flexCount, unsigned stream, const Args(&... args))
- : T(_Type::CalcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
-
- public:
- S m; ///< wrapped flexible structure
-
- /// Set stream-id. \retval true if the stream-id was successfully set.
- inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
-
- DEFINE_FLEXIBLE_METHODS(output, S)
- DEFINE_CAST_OPERATORS(output)
- };
-};
-
-/* ======================== SIMPLE VALUE PARAMETERS ======================== */
-
-/**
- * \ingroup internal
- * A structure template encapsulating a single element with default constructors and no core-index.
- */
-template<typename T>
-struct C2SimpleValueStruct {
- T value; ///< simple value of the structure
- // Default constructor.
- inline C2SimpleValueStruct() = default;
- // Constructor with an initial value.
- inline C2SimpleValueStruct(T value) : value(value) {}
- DEFINE_BASE_C2STRUCT(SimpleValue)
-};
-
-// TODO: move this and next to some generic place
-/**
- * Interface to a block of (mapped) memory containing an array of some type (T).
- */
-template<typename T>
-struct C2MemoryBlock {
- /// \returns the number of elements in this block.
- virtual size_t size() const = 0;
- /// \returns a const pointer to the start of this block. Care must be taken to not read outside
- /// the block.
- virtual const T *data() const = 0; // TODO: should this be friend access only in some C2Memory module?
- /// \returns a pointer to the start of this block. Care must be taken to not read or write
- /// outside the block.
- inline T *data() { return const_cast<T*>(data()); }
-protected:
- // TODO: for now it should never be deleted as C2MemoryBlock
- virtual ~C2MemoryBlock() = default;
-};
-
-/**
- * Interface to a block of memory containing a constant (constexpr) array of some type (T).
- */
-template<typename T>
-struct C2ConstMemoryBlock : public C2MemoryBlock<T> {
- virtual const T * data() const { return _mData; }
- virtual size_t size() const { return _mSize; }
-
- /// Constructor.
- template<unsigned N>
- inline constexpr C2ConstMemoryBlock(const T(&init)[N]) : _mData(init), _mSize(N) {}
-
-private:
- const T *_mData;
- const size_t _mSize;
-};
-
-/// \addtogroup internal
-/// @{
-
-/// Helper class to initialize flexible arrays with various initalizers.
-struct _C2ValueArrayHelper {
- // char[]-s are used as null terminated strings, so the last element is never inited.
-
- /// Initialize a flexible array using a constexpr memory block.
- template<typename T>
- static void init(T(&array)[], size_t arrayLen, const C2MemoryBlock<T> &block) {
- // reserve last element for terminal 0 for strings
- if (arrayLen && std::is_same<T, char>::value) {
- --arrayLen;
- }
- if (block.data()) {
- memcpy(array, block.data(), std::min(arrayLen, block.size()) * sizeof(T));
- }
- }
-
- /// Initialize a flexible array using an initializer list.
- template<typename T>
- static void init(T(&array)[], size_t arrayLen, const std::initializer_list<T> &init) {
- size_t ix = 0;
- // reserve last element for terminal 0 for strings
- if (arrayLen && std::is_same<T, char>::value) {
- --arrayLen;
- }
- for (const T &item : init) {
- if (ix == arrayLen) {
- break;
- }
- array[ix++] = item;
- }
- }
-
- /// Initialize a flexible array using another flexible array.
- template<typename T, unsigned N>
- static void init(T(&array)[], size_t arrayLen, const T(&str)[N]) {
- // reserve last element for terminal 0 for strings
- if (arrayLen && std::is_same<T, char>::value) {
- --arrayLen;
- }
- if (arrayLen) {
- strncpy(array, str, std::min(arrayLen, (size_t)N));
- }
- }
-};
-
-/**
- * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
- * flexible array member with default flexible constructors and no core-index. This type cannot be
- * constructed on its own as it's size is 0.
- *
- * \internal This is different from C2SimpleArrayStruct<T[]> simply because its member has the name
- * as value to reflect this is a single value.
- */
-template<typename T>
-struct C2SimpleValueStruct<T[]> {
- static_assert(std::is_same<T, char>::value || std::is_same<T, uint8_t>::value,
- "C2SimpleValueStruct<T[]> is only for BLOB or STRING");
- T value[];
-
- inline C2SimpleValueStruct() = default;
- DEFINE_BASE_C2STRUCT(SimpleValue)
- FLEX(C2SimpleValueStruct, value)
-
-private:
- inline C2SimpleValueStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
- _C2ValueArrayHelper::init(value, flexCount, block);
- }
-
- inline C2SimpleValueStruct(size_t flexCount, const std::initializer_list<T> &init) {
- _C2ValueArrayHelper::init(value, flexCount, init);
- }
-
- template<unsigned N>
- inline C2SimpleValueStruct(size_t flexCount, const T(&init)[N]) {
- _C2ValueArrayHelper::init(value, flexCount, init);
- }
-};
-
-/// @}
-
-/**
- * A structure template encapsulating a single flexible array element of a specific type (T) with
- * default constructors and no core-index. This type cannot be constructed on its own as it's size
- * is 0. Instead, it is meant to be used as a parameter, e.g.
- *
- * typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2MyFancyStruct>,
- * kParamIndexMyFancyArrayStreamParam> C2MyFancyArrayStreamInfo;
- */
-template<typename T>
-struct C2SimpleArrayStruct {
- static_assert(!std::is_same<T, char>::value && !std::is_same<T, uint8_t>::value,
- "use C2SimpleValueStruct<T[]> is for BLOB or STRING");
-
- T values[]; ///< array member
- /// Default constructor
- inline C2SimpleArrayStruct() = default;
- DEFINE_BASE_FLEX_C2STRUCT(SimpleArray, values)
- //FLEX(C2SimpleArrayStruct, values)
-
-private:
- /// Construct from a C2MemoryBlock.
- /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
- inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
- _C2ValueArrayHelper::init(values, flexCount, block);
- }
-
- /// Construct from an initializer list.
- /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
- inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
- _C2ValueArrayHelper::init(values, flexCount, init);
- }
-
- /// Construct from another flexible array.
- /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
- template<unsigned N>
- inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
- _C2ValueArrayHelper::init(values, flexCount, init);
- }
-};
-
-/**
- * \addtogroup simplevalue Simple value and array structures.
- * @{
- *
- * Simple value structures.
- *
- * Structures containing a single simple value. These can be reused to easily define simple
- * parameters of various types:
- *
- * typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexMyIntegerPortParam>
- * C2MyIntegerPortParamTuning;
- *
- * They contain a single member (value or values) that is described as "value" or "values".
- */
-/// A 32-bit signed integer parameter in value, described as "value"
-typedef C2SimpleValueStruct<int32_t> C2Int32Value;
-/// A 32-bit signed integer array parameter in values, described as "values"
-typedef C2SimpleArrayStruct<int32_t> C2Int32Array;
-/// A 32-bit unsigned integer parameter in value, described as "value"
-typedef C2SimpleValueStruct<uint32_t> C2Uint32Value;
-/// A 32-bit unsigned integer array parameter in values, described as "values"
-typedef C2SimpleArrayStruct<uint32_t> C2Uint32Array;
-/// A 64-bit signed integer parameter in value, described as "value"
-typedef C2SimpleValueStruct<int64_t> C2Int64Value;
-/// A 64-bit signed integer array parameter in values, described as "values"
-typedef C2SimpleArrayStruct<int64_t> C2Int64Array;
-/// A 64-bit unsigned integer parameter in value, described as "value"
-typedef C2SimpleValueStruct<uint64_t> C2Uint64Value;
-/// A 64-bit unsigned integer array parameter in values, described as "values"
-typedef C2SimpleArrayStruct<uint64_t> C2Uint64Array;
-/// A float parameter in value, described as "value"
-typedef C2SimpleValueStruct<float> C2FloatValue;
-/// A float array parameter in values, described as "values"
-typedef C2SimpleArrayStruct<float> C2FloatArray;
-/// A blob flexible parameter in value, described as "value"
-typedef C2SimpleValueStruct<uint8_t[]> C2BlobValue;
-/// A string flexible parameter in value, described as "value"
-typedef C2SimpleValueStruct<char[]> C2StringValue;
-
-#if 1
-template<typename T>
-const std::initializer_list<const C2FieldDescriptor> C2SimpleValueStruct<T>::FIELD_LIST = { C2FIELD(value, "value") };
-template<typename T>
-const std::initializer_list<const C2FieldDescriptor> C2SimpleValueStruct<T[]>::FIELD_LIST = { C2FIELD(value, "value") };
-template<typename T>
-const std::initializer_list<const C2FieldDescriptor> C2SimpleArrayStruct<T>::FIELD_LIST = { C2FIELD(values, "values") };
-#else
-// This seem to be able to be handled by the template above
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<int32_t>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint32_t>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<int64_t>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint64_t>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<float>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint8_t[]>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<char[]>, { C2FIELD(value, "value") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<int32_t>, { C2FIELD(values, "values") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<uint32_t>, { C2FIELD(values, "values") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<int64_t>, { C2FIELD(values, "values") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<uint64_t>, { C2FIELD(values, "values") });
-DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<float>, { C2FIELD(values, "values") });
-#endif
-
-/// @}
-
-/// @}
-
-#endif // C2PARAM_DEF_H_
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
deleted file mode 100644
index 1a35519..0000000
--- a/media/libstagefright/codec2/include/C2Work.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2WORK_H_
-
-#define C2WORK_H_
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <C2Param.h>
-#include <C2Buffer.h>
-#include <C2Config.h>
-
-#include <memory>
-#include <list>
-#include <vector>
-
-/// \defgroup work Work and data processing
-/// @{
-
-/**
- * Information describing the reason a parameter settings may fail, or
- * may be overriden.
- */
-struct C2SettingResult {
- enum Failure : uint32_t {
- /* parameter failures below */
- BAD_TYPE, ///< parameter is not supported
- BAD_PORT, ///< parameter is not supported on the specific port
- BAD_INDEX, ///< parameter is not supported on the specific stream
- READ_ONLY, ///< parameter is read-only and cannot be set
- MISMATCH, ///< parameter mismatches input data
-
- /* field failures below */
- BAD_VALUE, ///< parameter does not accept value for the field at all
- CONFLICT, ///< parameter field value is in conflict with an/other setting(s)
-
- /// parameter field is out of range due to other settings (this failure mode
- /// can only be used for strict calculated parameters)
- UNSUPPORTED,
-
- /// requested parameter value is in conflict with an/other setting(s)
- /// and has been corrected to the closest supported value. This failure
- /// mode is given to provide suggestion to the client as to how to
- /// enable the requested parameter value.
- INFO_CONFLICT,
- };
-
- Failure failure; ///< failure code
-
- /// Failing (or corrected) field or parameterand optionally, currently supported values for the
- /// field. Values must only be set for field failures other than BAD_VALUE, and only if they are
- /// different from the globally supported values (e.g. due to restrictions by another param or
- /// input data).
- C2ParamFieldValues field;
-
- /// Conflicting parameters or fields with optional suggestions with (optional) suggested values
- /// for any conflicting fields to avoid the conflict. Must only be set for CONFLICT, UNSUPPORTED
- /// and INFO_CONFLICT failure codes.
- std::vector<C2ParamFieldValues> conflicts;
-};
-
-// ================================================================================================
-// WORK
-// ================================================================================================
-
-/** Unique ID for a processing node. */
-typedef uint32_t c2_node_id_t;
-
-enum {
- kParamIndexWorkOrdinal,
-};
-
-/**
- * Information for ordering work items on a component port.
- */
-struct C2WorkOrdinalStruct {
-//public:
- c2_cntr64_t timestamp; /** frame timestamp in microseconds */
- c2_cntr64_t frameIndex; /** submission ordinal on the initial component */
- c2_cntr64_t customOrdinal; /** can be given by the component, e.g. decode order */
-
- DEFINE_AND_DESCRIBE_C2STRUCT(WorkOrdinal)
- C2FIELD(timestamp, "timestamp")
- C2FIELD(frameIndex, "frame-index")
- C2FIELD(customOrdinal, "custom-ordinal")
-};
-
-/**
- * This structure represents a Codec 2.0 frame with its metadata.
- *
- * A frame basically consists of an ordered sets of buffers, configuration changes and info buffers
- * along with some non-configuration metadata.
- */
-struct C2FrameData {
-//public:
- enum flags_t : uint32_t {
- /**
- * For input frames: no output frame shall be generated when processing this frame, but
- * metadata shall still be processed.
- * For output frames: this frame shall be discarded and but metadata is still valid.
- */
- FLAG_DROP_FRAME = (1 << 0),
- /**
- * This frame is the last frame of the current stream. Further frames are part of a new
- * stream.
- */
- FLAG_END_OF_STREAM = (1 << 1),
- /**
- * This frame shall be discarded with its metadata.
- * This flag is only set by components - e.g. as a response to the flush command.
- */
- FLAG_DISCARD_FRAME = (1 << 2),
- /**
- * This frame contains only codec-specific configuration data, and no actual access unit.
- *
- * \deprecated pass codec configuration with using the \todo codec-specific configuration
- * info together with the access unit.
- */
- FLAG_CODEC_CONFIG = (1u << 31),
- };
-
- /**
- * Frame flags */
- flags_t flags;
- C2WorkOrdinalStruct ordinal;
- std::vector<std::shared_ptr<C2Buffer>> buffers;
- //< for initial work item, these may also come from the parser - if provided
- //< for output buffers, these are the responses to requestedInfos
- std::vector<std::unique_ptr<C2Param>> configUpdate;
- std::vector<std::shared_ptr<C2InfoBuffer>> infoBuffers;
-};
-
-struct C2Worklet {
-//public:
- // IN
- c2_node_id_t component;
-
- /** Configuration changes to be applied before processing this worklet. */
- std::vector<std::unique_ptr<C2Tuning>> tunings;
- std::vector<std::unique_ptr<C2SettingResult>> failures;
-
- // OUT
- C2FrameData output;
-};
-
-/**
- * Information about partial work-chains not part of the current work items.
- *
- * To be defined later.
- */
-struct C2WorkChainInfo;
-
-/**
- * This structure holds information about all a single work item.
- *
- * This structure shall be passed by the client to the component for the first worklet. As such,
- * worklets must not be empty. The ownership of this object is passed.
- */
-struct C2Work {
-//public:
- /// additional work chain info not part of this work
- std::shared_ptr<C2WorkChainInfo> chainInfo;
-
- /// The input data to be processed as part of this work/work-chain. This is provided by the
- /// client with ownership. When the work is returned (via onWorkDone), the input buffer-pack's
- /// buffer vector shall contain nullptrs.
- C2FrameData input;
-
- /// The chain of components, tunings (including output buffer pool IDs) and info requests that the
- /// data must pass through. If this has more than a single element, the tunnels between successive
- /// components of the worklet chain must have been (successfully) pre-registered at the time that
- /// the work is submitted. Allocating the output buffers in the worklets is the responsibility of
- /// each component. Upon work submission, each output buffer-pack shall be an appropriately sized
- /// vector containing nullptrs. When the work is completed/returned to the client, output buffers
- /// pointers from all but the final worklet shall be nullptrs.
- std::list<std::unique_ptr<C2Worklet>> worklets;
-
- /// Number of worklets successfully processed in this chain. This shall be initialized to 0 by the
- /// client when the work is submitted. It shall contain the number of worklets that were
- /// successfully processed when the work is returned to the client. If this is less then the number
- /// of worklets, result must not be success. It must be in the range of [0, worklets.size()].
- uint32_t workletsProcessed;
-
- /// The final outcome of the work (corresponding to the current workletsProcessed). If 0 when
- /// work is returned, it is assumed that all worklets have been processed.
- c2_status_t result;
-};
-
-/**
- * Information about a future work to be submitted to the component. The information is used to
- * reserve the work for work ordering purposes.
- */
-struct C2WorkOutline {
-//public:
- C2WorkOrdinalStruct ordinal;
- std::vector<c2_node_id_t> chain;
-};
-
-/// @}
-
-#endif // C2WORK_H_
diff --git a/media/libstagefright/codec2/include/SimpleC2Component.h b/media/libstagefright/codec2/include/SimpleC2Component.h
deleted file mode 100644
index 168e79f..0000000
--- a/media/libstagefright/codec2/include/SimpleC2Component.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef SIMPLE_C2_COMPONENT_H_
-#define SIMPLE_C2_COMPONENT_H_
-
-#include <list>
-#include <thread>
-#include <unordered_map>
-
-#include <C2Component.h>
-
-#include <media/stagefright/foundation/Mutexed.h>
-
-namespace android {
-
-class SimpleC2Component
- : public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
-public:
- SimpleC2Component(
- const std::shared_ptr<C2ComponentInterface> &intf);
- virtual ~SimpleC2Component() = default;
-
- // C2Component
- // From C2Component
- virtual c2_status_t setListener_vb(
- const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override;
- virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
- virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
- virtual c2_status_t flush_sm(
- flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
- virtual c2_status_t drain_nb(drain_mode_t mode) override;
- virtual c2_status_t start() override;
- virtual c2_status_t stop() override;
- virtual c2_status_t reset() override;
- virtual c2_status_t release() override;
- virtual std::shared_ptr<C2ComponentInterface> intf() override;
-
- // for thread
- inline bool exitRequested() { return mExitRequested; }
- void processQueue();
- void signalExit();
-
-protected:
- /**
- * Initialize internal states of the component according to the config set
- * in the interface.
- *
- * This method is called during start(), but only at the first invocation or
- * after reset().
- */
- virtual c2_status_t onInit() = 0;
-
- /**
- * Stop the component.
- */
- virtual c2_status_t onStop() = 0;
-
- /**
- * Reset the component.
- */
- virtual void onReset() = 0;
-
- /**
- * Release the component.
- */
- virtual void onRelease() = 0;
-
- /**
- * Flush the component.
- */
- virtual c2_status_t onFlush_sm() = 0;
-
- /**
- * Process the given work and finish pending work using finish().
- *
- * \param[in,out] work the work to process
- * \param[in] pool the pool to use for allocating output blocks.
- */
- virtual void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) = 0;
-
- /**
- * Drain the component and finish pending work using finish().
- *
- * \param[in] drainMode mode of drain.
- * \param[in] pool the pool to use for allocating output blocks.
- *
- * \retval C2_OK The component has drained all pending output
- * work.
- * \retval C2_OMITTED Unsupported mode (e.g. DRAIN_CHAIN)
- */
- virtual c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) = 0;
-
- // for derived classes
- /**
- * Finish pending work.
- *
- * This method will retrieve the pending work according to |frameIndex| and
- * feed the work into |fillWork| function. |fillWork| must be
- * "non-blocking". Once |fillWork| returns the filled work will be returned
- * to the client.
- *
- * \param[in] frameIndex the index of the pending work
- * \param[in] fillWork the function to fill the retrieved work.
- */
- void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
-
- std::shared_ptr<C2Buffer> createLinearBuffer(
- const std::shared_ptr<C2LinearBlock> &block);
-
- std::shared_ptr<C2Buffer> createLinearBuffer(
- const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size);
-
- std::shared_ptr<C2Buffer> createGraphicBuffer(
- const std::shared_ptr<C2GraphicBlock> &block);
-
- std::shared_ptr<C2Buffer> createGraphicBuffer(
- const std::shared_ptr<C2GraphicBlock> &block,
- const C2Rect &crop);
-
- static constexpr uint32_t NO_DRAIN = ~0u;
-
-private:
- const std::shared_ptr<C2ComponentInterface> mIntf;
- std::atomic_bool mExitRequested;
-
- enum {
- UNINITIALIZED,
- STOPPED,
- RUNNING,
- };
-
- struct ExecState {
- ExecState() : mState(UNINITIALIZED) {}
-
- int mState;
- std::thread mThread;
- std::shared_ptr<C2Component::Listener> mListener;
- };
- Mutexed<ExecState> mExecState;
-
- class WorkQueue {
- public:
- inline WorkQueue() : mFlush(false), mGeneration(0ul) {}
-
- inline uint64_t generation() const { return mGeneration; }
- inline void incGeneration() { ++mGeneration; mFlush = true; }
-
- std::unique_ptr<C2Work> pop_front();
- void push_back(std::unique_ptr<C2Work> work);
- bool empty() const;
- uint32_t drainMode() const;
- void markDrain(uint32_t drainMode);
- inline bool popPendingFlush() {
- bool flush = mFlush;
- mFlush = false;
- return flush;
- }
- void clear();
-
- Condition mCondition;
-
- private:
- struct Entry {
- std::unique_ptr<C2Work> work;
- uint32_t drainMode;
- };
-
- bool mFlush;
- uint64_t mGeneration;
- std::list<Entry> mQueue;
- };
- Mutexed<WorkQueue> mWorkQueue;
-
- typedef std::unordered_map<uint64_t, std::unique_ptr<C2Work>> PendingWork;
- Mutexed<PendingWork> mPendingWork;
-
- struct ExitMonitor {
- inline ExitMonitor() : mExited(false) {}
- Condition mCondition;
- bool mExited;
- };
- Mutexed<ExitMonitor> mExitMonitor;
-
- std::shared_ptr<C2BlockPool> mOutputBlockPool;
-
- SimpleC2Component() = delete;
-
- void requestExitAndWait(std::function<void()> job);
-};
-
-} // namespace android
-
-#endif // SIMPLE_C2_COMPONENT_H_
diff --git a/media/libstagefright/codec2/include/SimpleC2Interface.h b/media/libstagefright/codec2/include/SimpleC2Interface.h
deleted file mode 100644
index 310096f..0000000
--- a/media/libstagefright/codec2/include/SimpleC2Interface.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef SIMPLE_C2_INTERFACE_H_
-#define SIMPLE_C2_INTERFACE_H_
-
-#include <C2Component.h>
-
-namespace android {
-
-class SimpleC2Interface : public C2ComponentInterface {
-public:
- class Builder {
- public:
- inline Builder(
- const char *name,
- c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>())
- : mIntf(new SimpleC2Interface(name, id), deleter) {}
-
- inline Builder &inputFormat(C2FormatKind input) {
- mIntf->mInputFormat.value = input;
- return *this;
- }
-
- inline Builder &outputFormat(C2FormatKind output) {
- mIntf->mOutputFormat.value = output;
- return *this;
- }
-
- inline Builder &inputMediaType(const char *mediaType, size_t maxLen = 128) {
- mIntf->mInputMediaType = C2PortMimeConfig::input::AllocShared(maxLen);
- std::strncpy(mIntf->mInputMediaType->m.value, mediaType, maxLen);
- return *this;
- }
-
- inline Builder &outputMediaType(const char *mediaType, size_t maxLen = 128) {
- mIntf->mOutputMediaType = C2PortMimeConfig::output::AllocShared(maxLen);
- std::strncpy(mIntf->mOutputMediaType->m.value, mediaType, maxLen);
- return *this;
- }
-
- template<size_t N>
- inline Builder &inputMediaType(const char mediaType[N]) {
- return inputMediaType(mediaType, N);
- }
-
- template<size_t N>
- inline Builder &outputMediaType(const char mediaType[N]) {
- return outputMediaType(mediaType, N);
- }
-
- inline std::shared_ptr<SimpleC2Interface> build() {
- return mIntf;
- }
- private:
- std::shared_ptr<SimpleC2Interface> mIntf;
- };
-
- virtual ~SimpleC2Interface() = default;
-
- // From C2ComponentInterface
- inline C2String getName() const override { return mName; }
- inline c2_node_id_t getId() const override { return mId; }
- c2_status_t query_vb(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
- inline c2_status_t config_vb(
- const std::vector<C2Param*> &,
- c2_blocking_t,
- std::vector<std::unique_ptr<C2SettingResult>>* const) override {
- return C2_OMITTED;
- }
- inline c2_status_t createTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
- inline c2_status_t releaseTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
- inline c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> * const) const override {
- return C2_OMITTED;
- }
- c2_status_t querySupportedValues_vb(
- std::vector<C2FieldSupportedValuesQuery> &,
- c2_blocking_t) const override {
- return C2_OMITTED;
- }
-
-private:
- inline SimpleC2Interface(const char *name, c2_node_id_t id)
- : mName(name), mId(id), mInputFormat(0u), mOutputFormat(0u) {}
-
- const C2String mName;
- const c2_node_id_t mId;
- C2StreamFormatConfig::input mInputFormat;
- C2StreamFormatConfig::output mOutputFormat;
- std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
- std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
-
- SimpleC2Interface() = delete;
-};
-
-} // namespace android
-
-#endif // SIMPLE_C2_INTERFACE_H_
diff --git a/media/libstagefright/codec2/include/android-C2Buffer.h b/media/libstagefright/codec2/include/android-C2Buffer.h
deleted file mode 100644
index c71f2cf..0000000
--- a/media/libstagefright/codec2/include/android-C2Buffer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef ANDROID_C2BUFFER_H_
-#define ANDROID_C2BUFFER_H_
-
-#include <cutils/native_handle.h>
-#include <hardware/gralloc.h>
-
-/* Use android native handle for C2Handle */
-typedef ::native_handle_t C2Handle;
-
-namespace android {
-
-/**
- * Android platform buffer/memory usage bits.
- */
-struct C2AndroidMemoryUsage : public C2MemoryUsage {
-// public:
- /**
- * Reuse gralloc flags where possible, as Codec 2.0 API only uses bits 0 and 1.
- */
- enum Consumer : uint64_t {
- RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
- HW_TEXTURE_READ = GRALLOC_USAGE_HW_TEXTURE,
- HW_COMPOSER_READ = GRALLOC_USAGE_HW_COMPOSER,
- HW_CODEC_READ = GRALLOC_USAGE_HW_VIDEO_ENCODER,
- READ_PROTECTED = GRALLOC_USAGE_PROTECTED,
- };
-
- enum Producer : uint64_t {
- RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
- HW_TEXTURE_WRITE = GRALLOC_USAGE_HW_RENDER,
- HW_COMPOSER_WRITE = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
- HW_CODEC_WRITE = GRALLOC_USAGE_HW_VIDEO_ENCODER,
- WRITE_PROTECTED = GRALLOC_USAGE_PROTECTED,
- };
-
- /**
- * Convert from gralloc usage.
- */
- static C2MemoryUsage FromGrallocUsage(uint64_t usage);
-
- /**
- * Convert to gralloc usage.
- */
- uint64_t asGrallocUsage() const;
-};
-
-} // namespace android
-
-#endif // ANDROID_C2BUFFER_H_
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
deleted file mode 100644
index b011a06..0000000
--- a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
-#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
-
-#include <memory>
-
-#include <C2Component.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
-
-namespace android {
-
-class GraphicBufferSource;
-
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::sp;
-
-typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
- HGraphicBufferProducer;
-typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
-
-// TODO: ::android::TWGraphicBufferProducer<IInputSurface>
-typedef ::android::TWGraphicBufferProducer<HGraphicBufferProducer> InputSurfaceBase;
-
-class InputSurface : public InputSurfaceBase {
-public:
- virtual ~InputSurface() = default;
-
- // Methods from IInputSurface
- sp<InputSurfaceConnection> connectToComponent(
- const std::shared_ptr<::C2Component> &comp);
- // TODO: intf()
-
- static sp<InputSurface> Create();
-
-private:
- InputSurface(
- const sp<BGraphicBufferProducer> &base,
- const sp<::android::GraphicBufferSource> &source);
-
- sp<::android::GraphicBufferSource> mSource;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
deleted file mode 100644
index b24a416..0000000
--- a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
-#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
-
-#include <memory>
-
-#include <C2Component.h>
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace implementation {
-
-// TODO: inherit from IInputSurfaceConnection
-class InputSurfaceConnection : public RefBase {
-public:
- virtual ~InputSurfaceConnection();
-
- // From IInputSurfaceConnection
- void disconnect();
-
-private:
- friend class InputSurface;
-
- // For InputSurface
- InputSurfaceConnection(
- const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp);
- bool init();
-
- InputSurfaceConnection() = delete;
-
- class Impl;
-
- sp<GraphicBufferSource> mSource;
- sp<Impl> mImpl;
-
- DISALLOW_EVIL_CONSTRUCTORS(InputSurfaceConnection);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
diff --git a/media/libstagefright/codec2/tests/Android.bp b/media/libstagefright/codec2/tests/Android.bp
deleted file mode 100644
index f26fbd0..0000000
--- a/media/libstagefright/codec2/tests/Android.bp
+++ /dev/null
@@ -1,90 +0,0 @@
-cc_test {
- name: "codec2_param_test",
-
- tags: [
- "tests",
- ],
-
- srcs: [
- "C2Param_test.cpp",
- "vndk/C2UtilTest.cpp",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright/codec2/include",
- "frameworks/av/media/libstagefright/codec2/vndk/include",
- ],
-
- // param tests must not depend on any codec2 libraries as all params should be templated
- shared_libs: [
- ],
-
- static_libs: [
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-std=c++14",
- ],
-}
-
-cc_test {
- name: "codec2_test",
-
- tags: [
- "tests",
- ],
-
- srcs: [
- "vndk/C2BufferTest.cpp",
- "C2_test.cpp",
- ],
-
- include_dirs: [
- ],
-
- shared_libs: [
- "libcutils",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-std=c++14",
- ],
-}
-
-cc_test {
- name: "codec2_interface_test",
-
- tags: [
- "tests",
- ],
-
- srcs: [
- "C2ComponentInterface_test.cpp",
- ],
-
- include_dirs: [
- "frameworks/native/include/media/openmax",
- ],
-
- shared_libs: [
- "libcutils",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-std=c++14",
- ],
-}
diff --git a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
deleted file mode 100644
index e555e8c..0000000
--- a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Copyright 2017 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_TAG "C2ComponentInterface_test"
-
-#include <dlfcn.h>
-#include <stdio.h>
-
-#include <gtest/gtest.h>
-#include <utils/Log.h>
-
-#include <C2Component.h>
-#include <C2Param.h>
-
-#if !defined(UNUSED)
-#define UNUSED(expr) \
- do { \
- (void)(expr); \
- } while (0)
-
-#endif //!defined(UNUSED)
-
-namespace android {
-
-template <class T> std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
- size_t len = strlen(cstr);
- std::unique_ptr<T> ptr = T::AllocUnique(len);
- memcpy(ptr->m.value, cstr, len);
- return ptr;
-}
-
-class C2CompIntfTest : public ::testing::Test {
-protected:
- C2CompIntfTest() {}
- ~C2CompIntfTest() override {}
-
- void setComponent(std::shared_ptr<C2ComponentInterface> intf) {
- mIntf = intf;
- }
-
- void resetResults() {
- mIntf = nullptr;
- mParamResults.clear();
- }
-
- template <typename T> void testUnsupportedParam();
-
- template <typename T> void testSupportedParam();
-
- // testReadOnlyParam() and testWritableParam() are the main functions for testing a parameter.
- // A caller should find out if a tested parameter is read-only or writable before calling them
- // and it must call one of the corresponded them.
-
- // If a parameter is read-only this is called.
- // Test read-only parameter |preParam|. The test expects failure while config() with |newParam|,
- // and make sure |preParam| stay unchanged.
- template <typename T>
- void testReadOnlyParam(const T &preParam, const T &newParam);
-
- // If a parameter is writable this is called.
- // Test one filed |writableField| for given writable parameter |param|.
- // |validValues| contains all values obtained from querySupportedValues() for |writableField|.
- // The test checks validity for config() with each value, and make sure values are config-ed
- // by query() them out. |invalidValues| contains some values which are not in |validValues|.
- // The test expects C2_BAD_VALUE while config() with these values,
- // and |param| should stay unchanged.
- template <typename TParam, typename TRealField, typename TField>
- void testWritableParam(TParam *const param, TRealField *const writableField,
- const std::vector<TField> &validValues,
- const std::vector<TField> &invalidValues);
-
- // Test all the defined parameters in C2Param.h.
- void testMain(std::shared_ptr<C2ComponentInterface> intf,
- const std::string &componentName);
-
- // Check permission of parameter type |T| for testing interface.
- // This should be called first of the testing per parameter type,
- // therefore different testing process is applied according to the permission type.
- template <typename T>
- void checkParamPermission(
- int *const writable,
- const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams);
-
-private:
- enum ParamPermission : int {
- WRITABLE,
- READONLY,
- UNSUPPORTED,
- };
-
- struct paramTestInfo {
- std::string name;
- int result;
- paramTestInfo(const char *name_, int result_)
- : name(name_), result(result_) {}
- };
-
- // queryOnStack() and queryonHeap() both call an interface's query_vb() and
- // check if a component has a parameter whose type is |T|.
- // If a component has, the value should be copied into an argument, that is
- // |p| in queryOnStack() and |heapParams| in queryOnHeap().
- // The return value is c2_status_t (e.g. C2_OK).
- template <typename T> c2_status_t queryOnStack(T *const p);
-
- template <typename T>
- c2_status_t queryOnHeap(const T &p,
- std::vector<std::unique_ptr<C2Param>> *const heapParams);
-
- // Get a value whose type is |T| in a component. The value is copied to |param|.
- // This should be called only if a component has the parameter.
- template <typename T> void getValue(T *const param);
-
- // Check if the parameter's value in component is equal to |expected| and
- // queryOnStack() and queryOnHeap() are succeeded. When this function called,
- // it should be guaranteed a component has the parameter.
- template <typename T> void queryParamAsExpected(const T &expected);
-
- // Test if query functions works correctly for supported parameters.
- // "Support" means here a component has the parameter.
- template <typename T> void querySupportedParam();
-
- // Test query functions works correctly for unsupported parameters.
- // "Unsupport" means here a component doesn't have the parameter.
- template <typename T> void queryUnsupportedParam();
-
- // Execute an interface's config_vb(). |T| is a single parameter type, not std::vector.
- // config() creates std::vector<C2Param *> {p} and passes it to config_vb().
- template <typename T>
- c2_status_t
- config(T *const p,
- std::vector<std::unique_ptr<C2SettingResult>> *const failures);
-
- // Test if config works correctly for read-only parameters.
- // Because the failure of config() is assumed, |newParam| doesn't matter.
- template <typename T> void configReadOnlyParam(const T &newParam);
-
- // Test if config works correctly for writable parameters.
- // This changes the parameter's value to |newParam|.
- // |stConfig| is a return value of config().
- template <typename T> void configWritableParamValidValue(const T &newParam, c2_status_t *stConfig);
-
- // Test if config works correctly in the case an invalid value |newParam| is tried to write
- // to an writable parameter.
- template <typename T> void configWritableParamInvalidValue(const T &newParam);
-
- // Create values for testing from |validValueInfos|. The values are returned as arguments.
- // |validValues| : valid values, which can be written for the parameter.
- // |InvalidValues| : invalid values, which cannot be written for the parameter.
- // config() should be failed if these values are used as new values.
- // This function should be called only for writable and supported parameters.
- template <typename TField>
- void getTestValues(const C2FieldSupportedValues &validValueInfos,
- std::vector<TField> *const validValues,
- std::vector<TField> *const invalidValues);
-
- // Output the summary of test results. Categorizes parameters with their configuration.
- void outputResults(const std::string &name);
-
- std::shared_ptr<C2ComponentInterface> mIntf;
- std::vector<paramTestInfo> mParamResults;
- std::string mCurrentParamName;
-};
-
-// factory function
-// TODO(hiroh): Add factory functions for other types.
-template <typename T> std::unique_ptr<T> makeParam() {
- return std::make_unique<T>();
-}
-
-template <> std::unique_ptr<C2PortMimeConfig::input> makeParam() {
- // TODO(hiroh): Set more precise length.
- return C2PortMimeConfig::input::AllocUnique(100);
-}
-
-#define TRACED_FAILURE(func) \
- do { \
- SCOPED_TRACE(mCurrentParamName); \
- func; \
- if (::testing::Test::HasFatalFailure()) { \
- return; \
- } \
- } while (false)
-
-template <typename T> c2_status_t C2CompIntfTest::queryOnStack(T *const p) {
- std::vector<C2Param*> stackParams{p};
- return mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr);
-}
-
-template <typename T>
-c2_status_t C2CompIntfTest::queryOnHeap(
- const T &p, std::vector<std::unique_ptr<C2Param>> *const heapParams) {
- uint32_t index = p.index() & ~0x03FE0000;
- if (p.forStream()) {
- index |= ((p.stream() << 17) & 0x01FE0000) | 0x02000000;
- }
- return mIntf->query_vb({}, {index}, C2_DONT_BLOCK, heapParams);
-}
-
-template <typename T> void C2CompIntfTest::getValue(T *const param) {
- // When getValue() is called, a component has to have the parameter.
- ASSERT_EQ(C2_OK, queryOnStack(param));
-}
-
-template <typename T>
-void C2CompIntfTest::queryParamAsExpected(const T &expected) {
- // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
- // Note that all the current supported parameters are non-flex params.
- T stack;
- std::unique_ptr<T> pHeap = makeParam<T>();
- std::vector<std::unique_ptr<C2Param>> heapParams;
-
- ASSERT_EQ(C2_OK, queryOnStack(&stack));
-
- // |stack| is a parameter value. The parameter size shouldn't be 0.
- EXPECT_NE(0u, stack.size());
- EXPECT_EQ(stack, expected);
-
- ASSERT_EQ(C2_OK, queryOnHeap(*pHeap, &heapParams));
-
- // |*heapParams[0]| is a parameter value. The size of |heapParams| has to be one.
- ASSERT_EQ(1u, heapParams.size());
- EXPECT_TRUE(heapParams[0]);
- EXPECT_EQ(*heapParams[0], expected);
-}
-
-template <typename T> void C2CompIntfTest::querySupportedParam() {
- std::unique_ptr<T> param = makeParam<T>();
- // The current parameter's value is acquired by getValue(), which should be succeeded.
- getValue(param.get());
- queryParamAsExpected(*param);
-}
-
-template <typename T> void C2CompIntfTest::queryUnsupportedParam() {
- // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
- // Note that all the current supported parameters are non-flex params.
- T stack;
- std::unique_ptr<T> pHeap = makeParam<T>();
- std::vector<std::unique_ptr<C2Param>> heapParams;
- // If a component doesn't have the parameter, queryOnStack() and queryOnHeap()
- // should return C2_BAD_INDEX.
- ASSERT_EQ(C2_BAD_INDEX, queryOnStack(&stack));
- EXPECT_FALSE(stack);
- ASSERT_EQ(C2_BAD_INDEX, queryOnHeap(*pHeap, &heapParams));
- EXPECT_EQ(0u, heapParams.size());
-}
-
-template <typename T>
-c2_status_t C2CompIntfTest::config(
- T *const p, std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
- std::vector<C2Param*> params{p};
- return mIntf->config_vb(params, C2_DONT_BLOCK, failures);
-}
-
-// Create a new parameter copied from |p|.
-template <typename T> std::unique_ptr<T> makeParamFrom(const T &p) {
- std::unique_ptr<T> retP = makeParam<T>();
- EXPECT_TRUE(retP->updateFrom(p));
- EXPECT_TRUE(memcmp(retP.get(), &p, sizeof(T)) == 0);
- return retP;
-}
-
-template <typename T>
-void C2CompIntfTest::configReadOnlyParam(const T &newParam) {
- std::unique_ptr<T> p = makeParamFrom(newParam);
-
- std::vector<C2Param*> params{p.get()};
- std::vector<std::unique_ptr<C2SettingResult>> failures;
-
- // config_vb should be failed because a parameter is read-only.
- ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
- ASSERT_EQ(1u, failures.size());
- EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure);
-}
-
-template <typename T>
-void C2CompIntfTest::configWritableParamValidValue(const T &newParam, c2_status_t *configResult) {
- std::unique_ptr<T> p = makeParamFrom(newParam);
-
- std::vector<C2Param*> params{p.get()};
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- // In most cases, config_vb return C2_OK and the parameter's value should be changed
- // to |newParam|, which is confirmed in a caller of configWritableParamValueValue().
- // However, this can return ~~~~ and the parameter's values is not changed,
- // because there may be dependent limitations between fields or between parameters.
- // TODO(hiroh): I have to fill the return value. Comments in C2Component.h doesn't mention
- // about the return value when conflict happens. I set C2_BAD_VALUE to it temporarily now.
- c2_status_t stConfig = mIntf->config_vb(params, C2_DONT_BLOCK, &failures);
- if (stConfig == C2_OK) {
- EXPECT_EQ(0u, failures.size());
- } else {
- ASSERT_EQ(C2_BAD_VALUE, stConfig);
- EXPECT_EQ(1u, failures.size());
- EXPECT_EQ(C2SettingResult::CONFLICT, failures[0]->failure);
- }
- *configResult = stConfig;
-}
-
-template <typename T>
-void C2CompIntfTest::configWritableParamInvalidValue(const T &newParam) {
- std::unique_ptr<T> p = makeParamFrom(newParam);
-
- std::vector<C2Param*> params{p.get()};
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- // Although a parameter is writable, config_vb should be failed,
- // because a new value is invalid.
- ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
- ASSERT_EQ(1u, failures.size());
- EXPECT_EQ(C2SettingResult::BAD_VALUE, failures[0]->failure);
-}
-
-// There is only used enum type for the field type, that is C2DomainKind.
-// If another field type is added, it is necessary to add function for that.
-template <>
-void C2CompIntfTest::getTestValues(
- const C2FieldSupportedValues &validValueInfos,
- std::vector<C2DomainKind> *const validValues,
- std::vector<C2DomainKind> *const invalidValues) {
- UNUSED(validValueInfos);
- validValues->emplace_back(C2DomainVideo);
- validValues->emplace_back(C2DomainAudio);
- validValues->emplace_back(C2DomainOther);
-
- // There is no invalid value.
- UNUSED(invalidValues);
-}
-
-template <typename TField>
-void C2CompIntfTest::getTestValues(
- const C2FieldSupportedValues &validValueInfos,
- std::vector<TField> *const validValues,
- std::vector<TField> *const invalidValues) {
-
- // The supported values are represented by C2Values. C2Value::Primitive needs to
- // be transformed to a primitive value. This function is one to do that.
- auto prim2Value = [](const C2Value::Primitive &prim) -> TField {
- if (std::is_same<TField, int32_t>::value) {
- return prim.i32;
- } else if (std::is_same<TField, uint32_t>::value) {
- return prim.u32;
- } else if (std::is_same<TField, int64_t>::value) {
- return prim.i64;
- } else if (std::is_same<TField, uint64_t>::value) {
- return prim.u64;
- } else if (std::is_same<TField, float>::value) {
- return prim.fp;
- }
- static_assert(std::is_same<TField, int32_t>::value ||
- std::is_same<TField, uint32_t>::value ||
- std::is_same<TField, int64_t>::value ||
- std::is_same<TField, uint64_t>::value ||
- std::is_same<TField, float>::value, "Invalid TField type.");
- return 0;
- };
-
- // The size of validValueInfos is one.
- const auto &c2FSV = validValueInfos;
-
- switch (c2FSV.type) {
- case C2FieldSupportedValues::type_t::EMPTY: {
- invalidValues->emplace_back(TField(0));
- // TODO(hiroh) : Should other invalid values be tested?
- break;
- }
- case C2FieldSupportedValues::type_t::RANGE: {
- const auto &range = c2FSV.range;
- auto rmin = prim2Value(range.min);
- auto rmax = prim2Value(range.max);
- auto rstep = prim2Value(range.step);
-
- ASSERT_LE(rmin, rmax);
-
- if (rstep != 0) {
- // Increase linear
- for (auto v = rmin; v <= rmax; v += rstep) {
- validValues->emplace_back(v);
- }
- if (rmin > std::numeric_limits<TField>::min()) {
- invalidValues->emplace_back(rmin - 1);
- }
- if (rmax < std::numeric_limits<TField>::max()) {
- invalidValues->emplace_back(rmax + 1);
- }
- const unsigned int N = validValues->size();
- if (N >= 2) {
- if (std::is_same<TField, float>::value) {
- invalidValues->emplace_back((validValues->at(0) + validValues->at(1)) / 2);
- invalidValues->emplace_back((validValues->at(N - 2) + validValues->at(N - 1)) / 2);
- } else {
- if (rstep > 1) {
- invalidValues->emplace_back(validValues->at(0) + 1);
- invalidValues->emplace_back(validValues->at(N - 1) - 1);
- }
- }
- }
- } else {
- // There should be two cases, except linear case.
- // 1. integer geometric case
- // 2. float geometric case
-
- auto num = prim2Value(range.num);
- auto denom = prim2Value(range.denom);
-
- // If both range.num and range.denom are 1 and step is 0, we should use
- // VALUES, shouldn't we?
- ASSERT_FALSE(num == 1 && denom == 1);
-
- // (num / denom) is not less than 1.
- ASSERT_FALSE(denom == 0);
- ASSERT_LE(denom, num);
- for (auto v = rmin; v <= rmax; v = v * num / denom) {
- validValues->emplace_back(v);
- }
-
- if (rmin > std::numeric_limits<TField>::min()) {
- invalidValues->emplace_back(rmin - 1);
- }
- if (rmax < std::numeric_limits<TField>::max()) {
- invalidValues->emplace_back(rmax + 1);
- }
-
- const unsigned int N = validValues->size();
- if (N >= 2) {
- if (std::is_same<TField, float>::value) {
- invalidValues->emplace_back((validValues->at(0) + validValues->at(1)) / 2);
- invalidValues->emplace_back((validValues->at(N - 2) + validValues->at(N - 1)) / 2);
- } else {
- if (validValues->at(1) - validValues->at(0) > 1) {
- invalidValues->emplace_back(validValues->at(0) + 1);
- }
- if (validValues->at(N - 1) - validValues->at(N - 2) > 1) {
- invalidValues->emplace_back(validValues->at(N - 1) - 1);
- }
- }
- }
- }
- break;
- }
- case C2FieldSupportedValues::type_t::VALUES: {
- for (const C2Value::Primitive &prim : c2FSV.values) {
- validValues->emplace_back(prim2Value(prim));
- }
- auto minv = *std::min_element(validValues->begin(), validValues->end());
- auto maxv = *std::max_element(validValues->begin(), validValues->end());
- if (minv - 1 > std::numeric_limits<TField>::min()) {
- invalidValues->emplace_back(minv - 1);
- }
- if (maxv + 1 < std::numeric_limits<TField>::max()) {
- invalidValues->emplace_back(maxv + 1);
- }
- break;
- }
- case C2FieldSupportedValues::type_t::FLAGS: {
- // TODO(hiroh) : Implement the case that param.type is FLAGS.
- break;
- }
- }
-}
-
-template <typename T>
-void C2CompIntfTest::testReadOnlyParam(const T &preParam, const T &newParam) {
- TRACED_FAILURE(configReadOnlyParam(newParam));
- // Parameter value must not be changed
- TRACED_FAILURE(queryParamAsExpected(preParam));
-}
-
-template <typename TParam, typename TRealField, typename TField>
-void C2CompIntfTest::testWritableParam(
- TParam *const param, TRealField *const writableField,
- const std::vector<TField> &validValues,
- const std::vector<TField> &invalidValues) {
- c2_status_t stConfig;
-
- // Get the parameter's value in the beginning in order to reset the value at the end.
- TRACED_FAILURE(getValue(param));
- std::unique_ptr<TParam> defaultParam = makeParamFrom(*param);
-
- // Test valid values
- for (const auto &val : validValues) {
- std::unique_ptr<TParam> preParam = makeParamFrom(*param);
-
- // Param is try to be changed
- *writableField = val;
- TRACED_FAILURE(configWritableParamValidValue(*param, &stConfig));
- if (stConfig == C2_OK) {
- TRACED_FAILURE(queryParamAsExpected(*param));
- } else {
- // Param is unchanged because a field value conflicts with other field or parameter.
- TRACED_FAILURE(queryParamAsExpected(*preParam));
- }
- }
-
- // Store the current parameter in order to test |param| is unchanged
- // after trying to write an invalid value.
- std::unique_ptr<TParam> lastValidParam = makeParamFrom(*param);
-
- // Test invalid values
- for (const auto &val : invalidValues) {
- // Param is changed
- *writableField = val;
- TRACED_FAILURE(configWritableParamInvalidValue(*param));
- TRACED_FAILURE(queryParamAsExpected(*lastValidParam));
- }
- // Reset the parameter by config().
- TRACED_FAILURE(configWritableParamValidValue(*defaultParam, &stConfig));
-}
-
-template <typename T> void C2CompIntfTest::testUnsupportedParam() {
- TRACED_FAILURE(queryUnsupportedParam<T>());
-}
-
-template <typename T> void C2CompIntfTest::testSupportedParam() {
- TRACED_FAILURE(querySupportedParam<T>());
-}
-
-bool isSupportedParam(
- const C2Param ¶m,
- const std::vector<std::shared_ptr<C2ParamDescriptor>> &sParams) {
- for (const auto &pd : sParams) {
- if (param.type() == pd->index().type()) {
- return true;
- }
- }
- return false;
-}
-
-template <typename T>
-void C2CompIntfTest::checkParamPermission(
- int *const result,
- const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams) {
- std::unique_ptr<T> param = makeParam<T>();
-
- if (!isSupportedParam(*param, supportedParams)) {
- // If a parameter isn't supported, it just finish after calling testUnsupportedParam().
- testUnsupportedParam<T>();
- *result = ParamPermission::UNSUPPORTED;
- return;
- }
-
- testSupportedParam<T>();
-
- TRACED_FAILURE(getValue(param.get()));
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- // Config does not change the parameter, because param is the present param.
- // This config is executed to find out if a parameter is read-only or writable.
- c2_status_t stStack = config(param.get(), &failures);
- if (stStack == C2_BAD_VALUE) {
- // Read-only
- std::unique_ptr<T> newParam = makeParam<T>();
- testReadOnlyParam(*param, *newParam);
- *result = ParamPermission::READONLY;
- } else {
- // Writable
- EXPECT_EQ(stStack, C2_OK);
- *result = ParamPermission::WRITABLE;
- }
-}
-
-void C2CompIntfTest::outputResults(const std::string &name) {
- std::vector<std::string> params[3];
- for (const auto &testInfo : mParamResults) {
- int result = testInfo.result;
- ASSERT_TRUE(0 <= result && result <= 2);
- params[result].emplace_back(testInfo.name);
- }
- const char *resultString[] = {"Writable", "Read-Only", "Unsupported"};
- printf("\n----TEST RESULTS (%s)----\n\n", name.c_str());
- for (int i = 0; i < 3; i++) {
- printf("[ %s ]\n", resultString[i]);
- for (const auto &t : params[i]) {
- printf("%s\n", t.c_str());
- }
- printf("\n");
- }
-}
-
-#define TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, field_name_) \
- do { \
- std::unique_ptr<TParam_> param = makeParam<TParam_>(); \
- std::vector<C2FieldSupportedValuesQuery> validValueInfos = { \
- C2FieldSupportedValuesQuery::Current( \
- C2ParamField(param.get(), &field_type_name_::field_name_)) \
- }; \
- ASSERT_EQ(C2_OK, \
- mIntf->querySupportedValues_vb(validValueInfos, C2_DONT_BLOCK)); \
- ASSERT_EQ(1u, validValueInfos.size()); \
- std::vector<decltype(param->field_name_)> validValues; \
- std::vector<decltype(param->field_name_)> invalidValues; \
- getTestValues(validValueInfos[0].values, &validValues, &invalidValues); \
- testWritableParam(param.get(), ¶m->field_name_, validValues,\
- invalidValues); \
- } while (0)
-
-#define TEST_VSSTRUCT_WRITABLE_FIELD(TParam_, field_type_name_) \
- do { \
- TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, width); \
- TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, height); \
- } while (0)
-
-#define TEST_U32_WRITABLE_FIELD(TParam_, field_type_name_) \
- TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
-
-#define TEST_ENUM_WRITABLE_FIELD(TParam_, field_type_name_) \
- TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
-
-// TODO(hiroh): Support parameters based on char[] and uint32_t[].
-//#define TEST_STRING_WRITABLE_FIELD(TParam_, field_type_name_)
-// TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, m.value)
-//#define TEST_U32ARRAY_WRITABLE_FIELD(Tparam_, field_type_name_)
-// TEST_GENERAL_WRITABLE_FIELD(Tparam_, uint32_t[], field_type_name_, values)
-
-#define EACH_TEST(TParam_, field_type_name_, test_name) \
- do { \
- int result = 0; \
- this->mCurrentParamName = #TParam_; \
- checkParamPermission<TParam_>(&result, supportedParams); \
- if (result == ParamPermission::WRITABLE) { \
- test_name(TParam_, field_type_name_); \
- } \
- mParamResults.emplace_back(#TParam_, result); \
- } while (0)
-
-#define EACH_TEST_SELF(type_, test_name) EACH_TEST(type_, type_, test_name)
-#define EACH_TEST_INPUT(type_, test_name) EACH_TEST(type_::input, type_, test_name)
-#define EACH_TEST_OUTPUT(type_, test_name) EACH_TEST(type_::output, type_, test_name)
-void C2CompIntfTest::testMain(std::shared_ptr<C2ComponentInterface> intf,
- const std::string &componentName) {
- setComponent(intf);
-
- std::vector<std::shared_ptr<C2ParamDescriptor>> supportedParams;
- ASSERT_EQ(C2_OK, mIntf->querySupportedParams_nb(&supportedParams));
-
- EACH_TEST_SELF(C2ComponentLatencyInfo, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_SELF(C2ComponentTemporalInfo, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_INPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_INPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_INPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
-
- EACH_TEST_SELF(C2ComponentDomainInfo, TEST_ENUM_WRITABLE_FIELD);
-
- // TODO(hiroh): Support parameters based on uint32_t[] and char[].
- // EACH_TEST_INPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
- // EACH_TEST_OUTPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
- // EACH_TEST_INPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
- // EACH_TEST_OUTPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
-
- // EACH_TEST_SELF(C2SupportedParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
- // EACH_TEST_SELF(C2RequiredParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
- // EACH_TEST_SELF(C2ReadOnlyParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
- // EACH_TEST_SELF(C2RequestedInfosInfo, TEST_U32ARRAY_WRITABLE_FIELD);
-
- EACH_TEST_INPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
- EACH_TEST_INPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
- EACH_TEST_INPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
- EACH_TEST_OUTPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
-
- outputResults(componentName);
- resetResults();
-}
-
-TEST_F(C2CompIntfTest, C2V4L2CodecIntf) {
-
- // Read a shared object library.
- void* compLib = dlopen("system/lib/libv4l2_codec2.so", RTLD_NOW);
-
- if (!compLib) {
- printf("Cannot open library: %s.\n", dlerror());
- FAIL();
- return;
- }
-
- typedef C2ComponentStore* create_t();
- create_t* create_store= (create_t*) dlsym(compLib, "create_store");
- const char* dlsym_error = dlerror();
- if (dlsym_error) {
- printf("Cannot load symbol create: %s.\n", dlsym_error);
- FAIL();
- return;
- }
-
- typedef void destroy_t(C2ComponentStore*);
- destroy_t* destroy_store = (destroy_t*) dlsym(compLib, "destroy_store");
- dlsym_error = dlerror();
- if (dlsym_error) {
- printf("Cannot load symbol destroy: %s.\n", dlsym_error);
- FAIL();
- return;
- }
-
- std::shared_ptr<C2ComponentStore> componentStore(create_store(), destroy_store);
- std::shared_ptr<C2ComponentInterface> componentIntf;
- componentStore->createInterface("v4l2.decoder", &componentIntf);
- auto componentName = "C2V4L2Codec";
- testMain(componentIntf, componentName);
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
deleted file mode 100644
index fcfbafd..0000000
--- a/media/libstagefright/codec2/tests/C2Param_test.cpp
+++ /dev/null
@@ -1,2931 +0,0 @@
-/*
- * Copyright 2016 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 "C2Param_test"
-
-#include <gtest/gtest.h>
-
-#define __C2_GENERATE_GLOBAL_VARS__
-#include <util/C2ParamUtils.h>
-#include <C2ParamDef.h>
-
-void PrintTo(const _C2FieldId &id, ::std::ostream* os) {
- *os << "@" << id._mOffset << "+" << id._mSize;
-}
-
-void PrintTo(const C2FieldDescriptor &fd, ::std::ostream *os) {
- using FD=C2FieldDescriptor;
- switch (fd.type()) {
- case FD::INT32: *os << "i32"; break;
- case FD::INT64: *os << "i64"; break;
- case FD::UINT32: *os << "u32"; break;
- case FD::UINT64: *os << "u64"; break;
- case FD::FLOAT: *os << "float"; break;
- case FD::STRING: *os << "char"; break;
- case FD::BLOB: *os << "u8"; break;
- default:
- if (fd.type() & FD::STRUCT_FLAG) {
- *os << "struct-" << (fd.type() & ~FD::STRUCT_FLAG);
- } else {
- *os << "type-" << fd.type();
- }
- }
- *os << " " << fd.name();
- if (fd.extent() > 1) {
- *os << "[" << fd.extent() << "]";
- } else if (fd.extent() == 0) {
- *os << "[]";
- }
- *os << " (";
- PrintTo(fd._mFieldId, os);
- *os << "*" << fd.extent() << ")";
-}
-
-enum C2ParamIndexType : C2Param::type_index_t {
- kParamIndexNumber,
- kParamIndexNumbers,
- kParamIndexNumber2,
- kParamIndexVendorStart = C2Param::TYPE_INDEX_VENDOR_START,
- kParamIndexVendorNumbers,
-};
-
-void ffff(int(*)(int)) {}
-
-/* ============================= STRUCT DECLARATION AND DESCRIPTION ============================= */
-
-typedef C2FieldDescriptor FD;
-
-class C2ParamTest : public ::testing::Test {
-};
-
-class C2ParamTest_ParamFieldList
- : public ::testing::TestWithParam<std::initializer_list<const C2FieldDescriptor>> {
-};
-
-enum {
- kParamIndexSize,
- kParamIndexTestA,
- kParamIndexTestB,
- kParamIndexTestFlexS32,
- kParamIndexTestFlexEndS32,
- kParamIndexTestFlexS64,
- kParamIndexTestFlexEndS64,
- kParamIndexTestFlexSize,
- kParamIndexTestFlexEndSize,
-};
-
-struct C2SizeStruct {
- int32_t width;
- int32_t height;
- enum : uint32_t { CORE_INDEX = kParamIndexSize }; // <= needed for C2FieldDescriptor
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST; // <= needed for C2FieldDescriptor
- const static FD::type_t TYPE = (FD::type_t)(CORE_INDEX | FD::STRUCT_FLAG);
-};
-
-DEFINE_NO_NAMED_VALUES_FOR(C2SizeStruct)
-
-// Test 1. define a structure without any helper methods
-
-bool operator==(const C2FieldDescriptor &a, const C2FieldDescriptor &b) {
- return a.type() == b.type()
- && a.extent() == b.extent()
- && strcmp(a.name(), b.name()) == 0
- && a._mFieldId == b._mFieldId;
-}
-
-struct C2TestStruct_A {
- int32_t signed32;
- int64_t signed64[2];
- uint32_t unsigned32[1];
- uint64_t unsigned64;
- float fp32;
- C2SizeStruct sz[3];
- uint8_t blob[100];
- char string[100];
- bool yesNo[100];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = kParamIndexTest };
- // typedef C2TestStruct_A _type;
-} __attribute__((packed));
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A::FIELD_LIST =
- { { FD::INT32, 1, "s32", 0, 4 },
- { FD::INT64, 2, "s64", 4, 8 },
- { FD::UINT32, 1, "u32", 20, 4 },
- { FD::UINT64, 1, "u64", 24, 8 },
- { FD::FLOAT, 1, "fp", 32, 4 },
- { C2SizeStruct::TYPE, 3, "size", 36, 8 },
- { FD::BLOB, 100, "blob", 60, 1 },
- { FD::STRING, 100, "str", 160, 1 },
- { FD::BLOB, 100, "y-n", 260, 1 } };
-
-TEST_P(C2ParamTest_ParamFieldList, VerifyStruct) {
- std::vector<const C2FieldDescriptor> fields = GetParam(), expected = C2TestStruct_A::FIELD_LIST;
-
- // verify first field descriptor
- EXPECT_EQ(FD::INT32, fields[0].type());
- EXPECT_STREQ("s32", fields[0].name());
- EXPECT_EQ(1u, fields[0].extent());
- EXPECT_EQ(_C2FieldId(0, 4), fields[0]._mFieldId);
-
- EXPECT_EQ(expected[0], fields[0]);
- EXPECT_EQ(expected[1], fields[1]);
- EXPECT_EQ(expected[2], fields[2]);
- EXPECT_EQ(expected[3], fields[3]);
- EXPECT_EQ(expected[4], fields[4]);
- EXPECT_EQ(expected[5], fields[5]);
- EXPECT_EQ(expected[6], fields[6]);
- EXPECT_EQ(expected[7], fields[7]);
- for (size_t i = 8; i < fields.size() && i < expected.size(); ++i) {
- EXPECT_EQ(expected[i], fields[i]);
- }
-}
-
-INSTANTIATE_TEST_CASE_P(InitializerList, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A::FIELD_LIST));
-
-// define fields using C2FieldDescriptor pointer constructor
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A_FD_PTR_fieldList =
- { C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->signed32, "s32"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->signed64, "s64"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->unsigned32, "u32"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->unsigned64, "u64"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->fp32, "fp"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->sz, "size"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->blob, "blob"),
- C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->string, "str"),
- // C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->yesNo, "y-n")
- };
-
-INSTANTIATE_TEST_CASE_P(PointerConstructor, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A_FD_PTR_fieldList));
-
-// define fields using C2FieldDescriptor member-pointer constructor
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A_FD_MEM_PTR_fieldList =
- { C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::signed32, "s32"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::signed64, "s64"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::unsigned32, "u32"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::unsigned64, "u64"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::fp32, "fp"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::sz, "size"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::blob, "blob"),
- C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::string, "str"),
- // C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::yesNo, "y-n")
- };
-
-INSTANTIATE_TEST_CASE_P(MemberPointerConstructor, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A_FD_MEM_PTR_fieldList));
-
-// Test 2. define a structure with two-step helper methods
-
-struct C2TestAStruct {
- int32_t signed32;
- int64_t signed64[2];
- uint32_t unsigned32[1];
- uint64_t unsigned64;
- float fp32;
- C2SizeStruct sz[3];
- uint8_t blob[100];
- char string[100];
- bool yesNo[100];
-
-private: // test access level
- DEFINE_C2STRUCT(TestA)
-} C2_PACK;
-
-DESCRIBE_C2STRUCT(TestA, {
- C2FIELD(signed32, "s32")
- C2FIELD(signed64, "s64")
- C2FIELD(unsigned32, "u32")
- C2FIELD(unsigned64, "u64")
- C2FIELD(fp32, "fp")
- C2FIELD(sz, "size")
- C2FIELD(blob, "blob")
- C2FIELD(string, "str")
- // C2FIELD(yesNo, "y-n")
-}) // ; optional
-
-INSTANTIATE_TEST_CASE_P(DescribeStruct2Step, C2ParamTest_ParamFieldList, ::testing::Values(C2TestAStruct::FIELD_LIST));
-
-// Test 3. define a structure with one-step helper method
-
-struct C2TestBStruct {
- int32_t signed32;
- int64_t signed64[2];
- uint32_t unsigned32[1];
- uint64_t unsigned64;
- float fp32;
- C2SizeStruct sz[3];
- uint8_t blob[100];
- char string[100];
- bool yesNo[100];
-
-private: // test access level
- DEFINE_AND_DESCRIBE_C2STRUCT(TestB)
-
- C2FIELD(signed32, "s32")
- C2FIELD(signed64, "s64")
- C2FIELD(unsigned32, "u32")
- C2FIELD(unsigned64, "u64")
- C2FIELD(fp32, "fp")
- C2FIELD(sz, "size")
- C2FIELD(blob, "blob")
- C2FIELD(string, "str")
- // C2FIELD(yesNo, "y-n")
-};
-
-INSTANTIATE_TEST_CASE_P(DescribeStruct1Step, C2ParamTest_ParamFieldList, ::testing::Values(C2TestBStruct::FIELD_LIST));
-
-// Test 4. flexible members
-
-template<typename T>
-class C2ParamTest_FlexParamFieldList : public ::testing::Test {
-protected:
- using type_t=FD::type_t;
-
- // static std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
- static std::vector<std::vector<const C2FieldDescriptor>>
- GetLists();
-
- constexpr static type_t FlexType =
- std::is_same<T, int32_t>::value ? FD::INT32 :
- std::is_same<T, int64_t>::value ? FD::INT64 :
- std::is_same<T, uint32_t>::value ? FD::UINT32 :
- std::is_same<T, uint64_t>::value ? FD::UINT64 :
- std::is_same<T, float>::value ? FD::FLOAT :
- std::is_same<T, uint8_t>::value ? FD::BLOB :
- std::is_same<T, char>::value ? FD::STRING :
- std::is_same<T, C2SizeStruct>::value ? C2SizeStruct::TYPE : (type_t)0;
- constexpr static size_t FLEX_SIZE = sizeof(T);
-};
-
-typedef ::testing::Types<int32_t, int64_t, C2SizeStruct> FlexTypes;
-TYPED_TEST_CASE(C2ParamTest_FlexParamFieldList, FlexTypes);
-
-TYPED_TEST(C2ParamTest_FlexParamFieldList, VerifyStruct) {
- for (auto a : this->GetLists()) {
- std::vector<const C2FieldDescriptor> fields = a;
- if (fields.size() > 1) {
- EXPECT_EQ(2u, fields.size());
- EXPECT_EQ(C2FieldDescriptor(FD::INT32, 1, "s32", 0, 4), fields[0]);
- EXPECT_EQ(C2FieldDescriptor(this->FlexType, 0, "flex", 4, this->FLEX_SIZE),
- fields[1]);
- } else {
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(C2FieldDescriptor(this->FlexType, 0, "flex", 0, this->FLEX_SIZE),
- fields[0]);
- }
- }
-}
-
-struct C2TestStruct_FlexS32 {
- int32_t mFlex[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = kParamIndexTestFlex, FLEX_SIZE = 4 };
- // typedef C2TestStruct_FlexS32 _type;
- // typedef int32_t FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexS32::FIELD_LIST = {
- { FD::INT32, 0, "flex", 0, 4 }
-};
-
-struct C2TestStruct_FlexEndS32 {
- int32_t signed32;
- int32_t mFlex[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = kParamIndexTestFlexEnd, FLEX_SIZE = 4 };
- // typedef C2TestStruct_FlexEnd _type;
- // typedef int32_t FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS32::FIELD_LIST = {
- { FD::INT32, 1, "s32", 0, 4 },
- { FD::INT32, 0, "flex", 4, 4 },
-};
-
-const static std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS32_ptr_fieldList = {
- C2FieldDescriptor(&((C2TestStruct_FlexEndS32*)0)->signed32, "s32"),
- C2FieldDescriptor(&((C2TestStruct_FlexEndS32*)0)->mFlex, "flex"),
-};
-
-struct C2TestFlexS32Struct {
- int32_t mFlexSigned32[];
-private: // test access level
- C2TestFlexS32Struct() {}
-
- DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexS32, mFlexSigned32)
- C2FIELD(mFlexSigned32, "flex")
-};
-
-struct C2TestFlexEndS32Struct {
- int32_t signed32;
- int32_t mFlexSigned32[];
-private: // test access level
- C2TestFlexEndS32Struct() {}
-
- DEFINE_FLEX_C2STRUCT(TestFlexEndS32, mFlexSigned32)
-} C2_PACK;
-
-DESCRIBE_C2STRUCT(TestFlexEndS32, {
- C2FIELD(signed32, "s32")
- C2FIELD(mFlexSigned32, "flex")
-}) // ; optional
-
-template<>
-std::vector<std::vector<const C2FieldDescriptor>>
-//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
-C2ParamTest_FlexParamFieldList<int32_t>::GetLists() {
- return {
- C2TestStruct_FlexS32::FIELD_LIST,
- C2TestStruct_FlexEndS32::FIELD_LIST,
- C2TestStruct_FlexEndS32_ptr_fieldList,
- C2TestFlexS32Struct::FIELD_LIST,
- C2TestFlexEndS32Struct::FIELD_LIST,
- };
-}
-
-struct C2TestStruct_FlexS64 {
- int64_t mFlexSigned64[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = kParamIndexTestFlexS64, FLEX_SIZE = 8 };
- // typedef C2TestStruct_FlexS64 _type;
- // typedef int64_t FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexS64::FIELD_LIST = {
- { FD::INT64, 0, "flex", 0, 8 }
-};
-
-struct C2TestStruct_FlexEndS64 {
- int32_t signed32;
- int64_t mSigned64Flex[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = C2TestStruct_FlexEndS64, FLEX_SIZE = 8 };
- // typedef C2TestStruct_FlexEndS64 _type;
- // typedef int64_t FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS64::FIELD_LIST = {
- { FD::INT32, 1, "s32", 0, 4 },
- { FD::INT64, 0, "flex", 4, 8 },
-};
-
-struct C2TestFlexS64Struct {
- int64_t mFlexSigned64[];
- C2TestFlexS64Struct() {}
-
- DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexS64, mFlexSigned64)
- C2FIELD(mFlexSigned64, "flex")
-};
-
-struct C2TestFlexEndS64Struct {
- int32_t signed32;
- int64_t mFlexSigned64[];
- C2TestFlexEndS64Struct() {}
-
- DEFINE_FLEX_C2STRUCT(TestFlexEndS64, mFlexSigned64)
-} C2_PACK;
-
-DESCRIBE_C2STRUCT(TestFlexEndS64, {
- C2FIELD(signed32, "s32")
- C2FIELD(mFlexSigned64, "flex")
-}) // ; optional
-
-template<>
-std::vector<std::vector<const C2FieldDescriptor>>
-//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
-C2ParamTest_FlexParamFieldList<int64_t>::GetLists() {
- return {
- C2TestStruct_FlexS64::FIELD_LIST,
- C2TestStruct_FlexEndS64::FIELD_LIST,
- C2TestFlexS64Struct::FIELD_LIST,
- C2TestFlexEndS64Struct::FIELD_LIST,
- };
-}
-
-struct C2TestStruct_FlexSize {
- C2SizeStruct mFlexSize[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = kParamIndexTestFlexSize, FLEX_SIZE = 8 };
- // typedef C2TestStruct_FlexSize _type;
- // typedef C2SizeStruct FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexSize::FIELD_LIST = {
- { C2SizeStruct::TYPE, 0, "flex", 0, sizeof(C2SizeStruct) }
-};
-
-struct C2TestStruct_FlexEndSize {
- int32_t signed32;
- C2SizeStruct mSizeFlex[];
-
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- // enum : uint32_t { CORE_INDEX = C2TestStruct_FlexEndSize, FLEX_SIZE = 8 };
- // typedef C2TestStruct_FlexEndSize _type;
- // typedef C2SizeStruct FlexType;
-};
-
-const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndSize::FIELD_LIST = {
- { FD::INT32, 1, "s32", 0, 4 },
- { C2SizeStruct::TYPE, 0, "flex", 4, sizeof(C2SizeStruct) },
-};
-
-struct C2TestFlexSizeStruct {
- C2SizeStruct mFlexSize[];
- C2TestFlexSizeStruct() {}
-
- DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexSize, mFlexSize)
- C2FIELD(mFlexSize, "flex")
-};
-
-struct C2TestFlexEndSizeStruct {
- int32_t signed32;
- C2SizeStruct mFlexSize[];
- C2TestFlexEndSizeStruct() {}
-
- DEFINE_FLEX_C2STRUCT(TestFlexEndSize, mFlexSize)
-} C2_PACK;
-
-DESCRIBE_C2STRUCT(TestFlexEndSize, {
- C2FIELD(signed32, "s32")
- C2FIELD(mFlexSize, "flex")
-}) // ; optional
-
-struct C2TestBaseFlexEndSizeStruct {
- int32_t signed32;
- C2SizeStruct mFlexSize[];
- C2TestBaseFlexEndSizeStruct() {}
-
- DEFINE_BASE_FLEX_C2STRUCT(TestBaseFlexEndSize, mFlexSize)
-} C2_PACK;
-
-DESCRIBE_C2STRUCT(TestBaseFlexEndSize, {
- C2FIELD(signed32, "s32")
- C2FIELD(mFlexSize, "flex")
-}) // ; optional
-
-struct C2TestBaseFlexEndSize2Struct {
- int32_t signed32;
- C2SizeStruct mFlexSize[];
- C2TestBaseFlexEndSize2Struct() {}
-
- DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(TestBaseFlexEndSize2, mFlexSize)
- C2FIELD(signed32, "s32")
- C2FIELD(mFlexSize, "flex")
-};
-
-template<>
-std::vector<std::vector<const C2FieldDescriptor>>
-//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
-C2ParamTest_FlexParamFieldList<C2SizeStruct>::GetLists() {
- return {
- C2TestStruct_FlexSize::FIELD_LIST,
- C2TestStruct_FlexEndSize::FIELD_LIST,
- C2TestFlexSizeStruct::FIELD_LIST,
- C2TestFlexEndSizeStruct::FIELD_LIST,
- C2TestBaseFlexEndSizeStruct::FIELD_LIST,
- C2TestBaseFlexEndSize2Struct::FIELD_LIST,
- };
-}
-
-TEST_F(C2ParamTest, FieldId) {
- // pointer constructor
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestStruct_A*)0)->signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestStruct_A*)0)->signed64));
- EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId(&((C2TestStruct_A*)0)->unsigned32));
- EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId(&((C2TestStruct_A*)0)->unsigned64));
- EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId(&((C2TestStruct_A*)0)->fp32));
- EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId(&((C2TestStruct_A*)0)->sz));
- EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId(&((C2TestStruct_A*)0)->blob));
- EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId(&((C2TestStruct_A*)0)->string));
- EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId(&((C2TestStruct_A*)0)->yesNo));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->mFlexSize));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestBaseFlexEndSizeStruct*)0)->signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestBaseFlexEndSizeStruct*)0)->mFlexSize));
-
- // member pointer constructor
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::signed64));
- EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::unsigned32));
- EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::unsigned64));
- EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::fp32));
- EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::sz));
- EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::blob));
- EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::string));
- EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::yesNo));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::mFlexSize));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestBaseFlexEndSizeStruct*)0, &C2TestBaseFlexEndSizeStruct::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestBaseFlexEndSizeStruct*)0, &C2TestBaseFlexEndSizeStruct::mFlexSize));
-
- // member pointer sans type pointer
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestStruct_A::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestStruct_A::signed64));
- EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId(&C2TestStruct_A::unsigned32));
- EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId(&C2TestStruct_A::unsigned64));
- EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId(&C2TestStruct_A::fp32));
- EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId(&C2TestStruct_A::sz));
- EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId(&C2TestStruct_A::blob));
- EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId(&C2TestStruct_A::string));
- EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId(&C2TestStruct_A::yesNo));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestFlexEndSizeStruct::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestFlexEndSizeStruct::mFlexSize));
-
- EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestBaseFlexEndSizeStruct::signed32));
- EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestBaseFlexEndSizeStruct::mFlexSize));
-
- typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
- typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
- typedef C2GlobalParam<C2Info, C2TestBaseFlexEndSizeStruct, kParamIndexTestFlexEndSize> C2TestFlexEndSizeInfoFromBase;
-
- // pointer constructor in C2Param
- EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestAInfo*)0)->signed32));
- EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestAInfo*)0)->signed64));
- EXPECT_EQ(_C2FieldId(28, 4), _C2FieldId(&((C2TestAInfo*)0)->unsigned32));
- EXPECT_EQ(_C2FieldId(32, 8), _C2FieldId(&((C2TestAInfo*)0)->unsigned64));
- EXPECT_EQ(_C2FieldId(40, 4), _C2FieldId(&((C2TestAInfo*)0)->fp32));
- EXPECT_EQ(_C2FieldId(44, 8), _C2FieldId(&((C2TestAInfo*)0)->sz));
- EXPECT_EQ(_C2FieldId(68, 1), _C2FieldId(&((C2TestAInfo*)0)->blob));
- EXPECT_EQ(_C2FieldId(168, 1), _C2FieldId(&((C2TestAInfo*)0)->string));
- EXPECT_EQ(_C2FieldId(268, 1), _C2FieldId(&((C2TestAInfo*)0)->yesNo));
-
- EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.signed32));
- EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.mFlexSize));
-
- EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestFlexEndSizeInfoFromBase*)0)->m.signed32));
- EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestFlexEndSizeInfoFromBase*)0)->m.mFlexSize));
-
- // member pointer in C2Param
- EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::signed32));
- EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::signed64));
- EXPECT_EQ(_C2FieldId(28, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::unsigned32));
- EXPECT_EQ(_C2FieldId(32, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::unsigned64));
- EXPECT_EQ(_C2FieldId(40, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::fp32));
- EXPECT_EQ(_C2FieldId(44, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::sz));
- EXPECT_EQ(_C2FieldId(68, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::blob));
- EXPECT_EQ(_C2FieldId(168, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::string));
- EXPECT_EQ(_C2FieldId(268, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::yesNo));
-
- // NOTE: cannot use a member pointer for flex params due to introduction of 'm'
- // EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&C2TestFlexEndSizeInfo::m.signed32));
- // EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&C2TestFlexEndSizeInfo::m.mFlexSize));
-
- // EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&C2TestFlexEndSizeInfoFromBase::m.signed32));
- // EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&C2TestFlexEndSizeInfoFromBase::m.mFlexSize));
-
-
-}
-
-struct S32 {
- template<typename T, class B=typename std::remove_extent<T>::type>
- inline S32(const T*) {
- static_assert(!std::is_array<T>::value, "should not be an array");
- static_assert(std::is_same<B, int32_t>::value, "should be int32_t");
- }
-};
-
-struct FLX {
- template<typename U, typename T, class B=typename std::remove_extent<T>::type>
- inline FLX(const T*, const U*) {
- static_assert(std::is_array<T>::value, "should be an array");
- static_assert(std::extent<T>::value == 0, "should be an array of 0 extent");
- static_assert(std::is_same<B, U>::value, "should be type U");
- }
-};
-
-struct MP {
- template<typename U, typename T, typename ExpectedU, typename UnexpectedU>
- inline MP(T U::*, const ExpectedU*, const UnexpectedU*) {
- static_assert(!std::is_same<U, UnexpectedU>::value, "should not be member pointer of the base type");
- static_assert(std::is_same<U, ExpectedU>::value, "should be member pointer of the derived type");
- }
-
- template<typename U, typename T, typename B, typename D>
- inline MP(T D::*, const D*) { }
-};
-
-void compiledStatic_arrayTypePropagationTest() {
- (void)S32(&((C2TestFlexEndS32Struct *)0)->signed32);
- (void)FLX(&((C2TestFlexEndS32Struct *)0)->mFlexSigned32, (int32_t*)0);
- (void)FLX(&((C2TestFlexS32Struct *)0)->mFlexSigned32, (int32_t*)0);
-
- typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
-
- // TRICKY: &derivedClass::baseMember has type of baseClass::*
- static_assert(std::is_same<decltype(&C2TestAInfo::signed32), int32_t C2TestAStruct::*>::value,
- "base member pointer should have base class in type");
-
- // therefore, member pointer expands to baseClass::* in templates
- (void)MP(&C2TestAInfo::signed32,
- (C2TestAStruct*)0 /* expected */, (C2TestAInfo*)0 /* unexpected */);
- // but can be cast to derivedClass::*
- (void)MP((int32_t C2TestAInfo::*)&C2TestAInfo::signed32,
- (C2TestAInfo*)0 /* expected */, (C2TestAStruct*)0 /* unexpected */);
-
- // TRICKY: baseClass::* does not autoconvert to derivedClass::* even in templates
- // (void)MP(&C2TestAInfo::signed32, (C2TestAInfo*)0);
-}
-
-TEST_F(C2ParamTest, MemberPointerCast) {
- typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
-
- static_assert(offsetof(C2TestAInfo, signed32) == 8, "offset should be 8");
- constexpr int32_t C2TestAStruct::* s32ptr = &C2TestAInfo::signed32;
- constexpr int32_t C2TestAInfo::* s32ptr_derived = (int32_t C2TestAStruct::*)&C2TestAInfo::signed32;
- constexpr int32_t C2TestAInfo::* s32ptr_cast2derived = (int32_t C2TestAInfo::*)s32ptr;
- C2TestAInfo *info = (C2TestAInfo *)256;
- C2TestAStruct *strukt = (C2TestAStruct *)info;
- int32_t *info_s32_derived = &(info->*s32ptr_derived);
- int32_t *info_s32_cast2derived = &(info->*s32ptr_cast2derived);
- int32_t *info_s32 = &(info->*s32ptr);
- int32_t *strukt_s32 = &(strukt->*s32ptr);
-
- EXPECT_EQ(256u, (uintptr_t)info);
- EXPECT_EQ(264u, (uintptr_t)strukt);
- EXPECT_EQ(264u, (uintptr_t)info_s32_derived);
- EXPECT_EQ(264u, (uintptr_t)info_s32_cast2derived);
- EXPECT_EQ(264u, (uintptr_t)info_s32);
- EXPECT_EQ(264u, (uintptr_t)strukt_s32);
-
- typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
- static_assert(offsetof(C2TestFlexEndSizeInfo, m.signed32) == 8, "offset should be 8");
- static_assert(offsetof(C2TestFlexEndSizeInfo, m.mFlexSize) == 12, "offset should be 12");
-
- typedef C2GlobalParam<C2Info, C2TestBaseFlexEndSizeStruct, kParamIndexTestFlexEndSize> C2TestFlexEndSizeInfoFromBase;
- static_assert(offsetof(C2TestFlexEndSizeInfoFromBase, m.signed32) == 8, "offset should be 8");
- static_assert(offsetof(C2TestFlexEndSizeInfoFromBase, m.mFlexSize) == 12, "offset should be 12");
-}
-
-/* ===================================== PARAM USAGE TESTS ===================================== */
-
-struct C2NumberStruct {
- int32_t mNumber;
- C2NumberStruct() {}
- C2NumberStruct(int32_t _number) : mNumber(_number) {}
-
- DEFINE_AND_DESCRIBE_C2STRUCT(Number)
- C2FIELD(mNumber, "number")
-};
-
-struct C2NumberBaseStruct {
- int32_t mNumber;
- C2NumberBaseStruct() {}
- C2NumberBaseStruct(int32_t _number) : mNumber(_number) {}
-
- DEFINE_AND_DESCRIBE_BASE_C2STRUCT(NumberBase)
- C2FIELD(mNumber, "number")
-};
-
-struct C2NumbersStruct {
- int32_t mNumbers[];
- C2NumbersStruct() {}
-
- DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(Numbers, mNumbers)
- C2FIELD(mNumbers, "numbers")
-};
-static_assert(sizeof(C2NumbersStruct) == 0, "C2NumbersStruct has incorrect size");
-
-typedef C2GlobalParam<C2Info, C2NumberStruct> C2NumberInfo;
-
-typedef C2GlobalParam<C2Tuning, C2NumberStruct> C2NumberTuning;
-typedef C2PortParam<C2Tuning, C2NumberStruct> C2NumberPortTuning;
-typedef C2StreamParam<C2Tuning, C2NumberStruct> C2NumberStreamTuning;
-
-typedef C2GlobalParam<C2Tuning, C2NumbersStruct> C2NumbersTuning;
-typedef C2PortParam<C2Tuning, C2NumbersStruct> C2NumbersPortTuning;
-typedef C2StreamParam<C2Tuning, C2NumbersStruct> C2NumbersStreamTuning;
-
-//
-#if 0
-
-void test() {
- C2NumberStruct s(10);
- (void)C2NumberStruct::FIELD_LIST;
-};
-
-typedef C2StreamParam<C2Tuning, C2Int64Value, kParamIndexNumberB> C2NumberConfig4;
-typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexNumber> C2NumberConfig3;
-typedef C2GlobalParam<C2Tuning, C2StringValue, kParamIndexNumber> C2VideoNameConfig;
-
-void test3() {
- C2NumberConfig3 s(10);
- s.value = 11;
- s = 12;
- (void)C2NumberConfig3::FIELD_LIST;
- std::shared_ptr<C2VideoNameConfig> n = C2VideoNameConfig::AllocShared(25);
- strcpy(n->m.value, "lajos");
- C2NumberConfig4 t(false, 0, 11);
- t.value = 15;
-};
-
-struct C2NumbersStruct {
- int32_t mNumbers[];
- enum { CORE_INDEX = kParamIndexNumber };
- const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST;
- C2NumbersStruct() {}
-
- FLEX(C2NumbersStruct, mNumbers);
-};
-
-static_assert(sizeof(C2NumbersStruct) == 0, "yes");
-
-
-typedef C2GlobalParam<C2Info, C2NumbersStruct> C2NumbersInfo;
-
-const std::initializer_list<const C2FieldDescriptor> C2NumbersStruct::FIELD_LIST =
-// { { FD::INT32, 0, "widths" } };
- { C2FieldDescriptor(&((C2NumbersStruct*)(nullptr))->mNumbers, "number") };
-
-typedef C2PortParam<C2Tuning, C2NumberStruct> C2NumberConfig;
-
-std::list<const C2FieldDescriptor> myList = C2NumberConfig::FIELD_LIST;
-
- std::unique_ptr<C2ParamDescriptor> __test_describe(uint32_t paramType) {
- std::list<const C2FieldDescriptor> fields = describeC2Params<C2NumberConfig>();
-
- auto widths = C2NumbersInfo::AllocShared(5);
- widths->flexCount();
- widths->m.mNumbers[4] = 1;
-
- test();
- test3();
-
- C2NumberConfig outputWidth(false, 123);
-
- C2Param::Index index(paramType);
- switch (paramType) {
- case C2NumberConfig::CORE_INDEX:
- return std::unique_ptr<C2ParamDescriptor>(new C2ParamDescriptor{
- true /* isRequired */,
- "number",
- index,
- });
- }
- return nullptr;
- }
-
-
-} // namespace android
-
-#endif
-//
-
-template<typename T>
-bool canSetPort(T &o, bool output) { return o.setPort(output); }
-bool canSetPort(...) { return false; }
-
-template<typename S, typename=decltype(((S*)0)->setPort(true))>
-static std::true_type _canCallSetPort(int);
-template<typename>
-static std::false_type _canCallSetPort(...);
-#define canCallSetPort(x) decltype(_canCallSetPort<std::remove_reference<decltype(x)>::type>(0))::value
-
-/* ======================================= STATIC TESTS ======================================= */
-
-static_assert(_C2Comparable<int>::value, "int is not comparable");
-static_assert(!_C2Comparable<void>::value, "void is comparable");
-
-struct C2_HIDE _test0 {
- bool operator==(const _test0&);
- bool operator!=(const _test0&);
-};
-struct C2_HIDE _test1 {
- bool operator==(const _test1&);
-};
-struct C2_HIDE _test2 {
- bool operator!=(const _test2&);
-};
-static_assert(_C2Comparable<_test0>::value, "class with == and != is not comparable");
-static_assert(_C2Comparable<_test1>::value, "class with == is not comparable");
-static_assert(_C2Comparable<_test2>::value, "class with != is not comparable");
-
-/* ======================================= C2PARAM TESTS ======================================= */
-
-struct _C2ParamInspector {
- static void StaticTest();
- static void StaticFromBaseTest();
- static void StaticFlexTest();
- static void StaticFlexFromBaseTest();
-};
-
-// TEST_F(_C2ParamInspector, StaticTest) {
-void _C2ParamInspector::StaticTest() {
- typedef C2Param::Index I;
-
- // C2NumberStruct: CORE_INDEX = kIndex (args)
- static_assert(C2NumberStruct::CORE_INDEX == kParamIndexNumber, "bad index");
- static_assert(sizeof(C2NumberStruct) == 4, "bad size");
-
- // C2NumberTuning: kIndex | tun | global (args)
- static_assert(C2NumberTuning::CORE_INDEX == kParamIndexNumber, "bad index");
- static_assert(C2NumberTuning::PARAM_TYPE == (kParamIndexNumber | I::KIND_TUNING | I::DIR_GLOBAL), "bad index");
- static_assert(sizeof(C2NumberTuning) == 12, "bad size");
-
- static_assert(offsetof(C2NumberTuning, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumberTuning, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumberTuning, mNumber) == 8, "bad offset");
-
- // C2NumberPortTuning: kIndex | tun | port (bool, args)
- static_assert(sizeof(C2NumberPortTuning) == 12, "bad size");
- // C2NumberPortTuning::input: kIndex | tun | port | input (args)
- // C2NumberPortTuning::output: kIndex | tun | port | output (args)
- static_assert(C2NumberPortTuning::input::CORE_INDEX ==
- kParamIndexNumber, "bad index");
- static_assert(C2NumberPortTuning::input::PARAM_TYPE ==
- (kParamIndexNumber | I::KIND_TUNING | I::DIR_INPUT), "bad index");
- static_assert(C2NumberPortTuning::output::CORE_INDEX ==
- kParamIndexNumber, "bad index");
- static_assert(C2NumberPortTuning::output::PARAM_TYPE ==
- (kParamIndexNumber | I::KIND_TUNING | I::DIR_OUTPUT), "bad index");
- static_assert(sizeof(C2NumberPortTuning::input) == 12, "bad size");
- static_assert(sizeof(C2NumberPortTuning::output) == 12, "bad size");
- static_assert(offsetof(C2NumberPortTuning::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumberPortTuning::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumberPortTuning::input, mNumber) == 8, "bad offset");
- static_assert(offsetof(C2NumberPortTuning::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumberPortTuning::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumberPortTuning::output, mNumber) == 8, "bad offset");
-
- // C2NumberStreamTuning: kIndex | tun | str (bool, uint, args)
- static_assert(sizeof(C2NumberStreamTuning) == 12u, "bad size");
- // C2NumberStreamTuning::input kIndex | tun | str | input (int, args)
- // C2NumberStreamTuning::output kIx | tun | str | output (int, args)
- static_assert(C2NumberStreamTuning::input::CORE_INDEX ==
- kParamIndexNumber, "bad index");
- static_assert(C2NumberStreamTuning::input::PARAM_TYPE ==
- (kParamIndexNumber | I::KIND_TUNING | I::DIR_INPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(C2NumberStreamTuning::output::CORE_INDEX ==
- kParamIndexNumber, "bad index");
- static_assert(C2NumberStreamTuning::output::PARAM_TYPE ==
- (kParamIndexNumber | I::KIND_TUNING | I::DIR_OUTPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(sizeof(C2NumberStreamTuning::input) == 12u, "bad size");
- static_assert(sizeof(C2NumberStreamTuning::output) == 12u, "bad size");
- static_assert(offsetof(C2NumberStreamTuning::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumberStreamTuning::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumberStreamTuning::input, mNumber) == 8, "bad offset");
- static_assert(offsetof(C2NumberStreamTuning::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumberStreamTuning::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumberStreamTuning::output, mNumber) == 8, "bad offset");
-}
-
-void _C2ParamInspector::StaticFromBaseTest() {
- enum { kParamIndexMy = 3102 };
- typedef C2NumberBaseStruct C2MyStruct;
- typedef C2GlobalParam<C2Setting, C2MyStruct, kParamIndexMy> C2MySetting;
- typedef C2PortParam<C2Setting, C2MyStruct, kParamIndexMy> C2MyPortSetting;
- typedef C2StreamParam<C2Setting, C2MyStruct, kParamIndexMy> C2MyStreamSetting;
-
- typedef C2Param::Index I;
-
- // C2MyStruct has no CORE_INDEX
- //static_assert(C2MyStruct::CORE_INDEX == kParamIndexMy, "bad index");
- static_assert(sizeof(C2MyStruct) == 4, "bad size");
-
- // C2MySetting: kIndex | tun | global (args)
- static_assert(C2MySetting::CORE_INDEX == kParamIndexMy, "bad index");
- static_assert(C2MySetting::PARAM_TYPE == (kParamIndexMy | I::KIND_SETTING | I::DIR_GLOBAL), "bad index");
- static_assert(sizeof(C2MySetting) == 12, "bad size");
-
- static_assert(offsetof(C2MySetting, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MySetting, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MySetting, mNumber) == 8, "bad offset");
-
- // C2MyPortSetting: kIndex | tun | port (bool, args)
- static_assert(sizeof(C2MyPortSetting) == 12, "bad size");
- // C2MyPortSetting::input: kIndex | tun | port | input (args)
- // C2MyPortSetting::output: kIndex | tun | port | output (args)
- static_assert(C2MyPortSetting::input::CORE_INDEX ==
- kParamIndexMy, "bad index");
- static_assert(C2MyPortSetting::input::PARAM_TYPE ==
- (kParamIndexMy | I::KIND_SETTING | I::DIR_INPUT), "bad index");
- static_assert(C2MyPortSetting::output::CORE_INDEX ==
- kParamIndexMy, "bad index");
- static_assert(C2MyPortSetting::output::PARAM_TYPE ==
- (kParamIndexMy | I::KIND_SETTING | I::DIR_OUTPUT), "bad index");
- static_assert(sizeof(C2MyPortSetting::input) == 12, "bad size");
- static_assert(sizeof(C2MyPortSetting::output) == 12, "bad size");
- static_assert(offsetof(C2MyPortSetting::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyPortSetting::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyPortSetting::input, mNumber) == 8, "bad offset");
- static_assert(offsetof(C2MyPortSetting::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyPortSetting::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyPortSetting::output, mNumber) == 8, "bad offset");
-
- // C2MyStreamSetting: kIndex | tun | str (bool, uint, args)
- static_assert(sizeof(C2MyStreamSetting) == 12u, "bad size");
- // C2MyStreamSetting::input kIndex | tun | str | input (int, args)
- // C2MyStreamSetting::output kIx | tun | str | output (int, args)
- static_assert(C2MyStreamSetting::input::CORE_INDEX ==
- kParamIndexMy, "bad index");
- static_assert(C2MyStreamSetting::input::PARAM_TYPE ==
- (kParamIndexMy | I::KIND_SETTING | I::DIR_INPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(C2MyStreamSetting::output::CORE_INDEX ==
- kParamIndexMy, "bad index");
- static_assert(C2MyStreamSetting::output::PARAM_TYPE ==
- (kParamIndexMy | I::KIND_SETTING | I::DIR_OUTPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(sizeof(C2MyStreamSetting::input) == 12u, "bad size");
- static_assert(sizeof(C2MyStreamSetting::output) == 12u, "bad size");
- static_assert(offsetof(C2MyStreamSetting::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyStreamSetting::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyStreamSetting::input, mNumber) == 8, "bad offset");
- static_assert(offsetof(C2MyStreamSetting::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyStreamSetting::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyStreamSetting::output, mNumber) == 8, "bad offset");
-}
-
-void _C2ParamInspector::StaticFlexTest() {
- typedef C2Param::Index I;
-
- // C2NumbersStruct: CORE_INDEX = kIndex (args)
- static_assert(C2NumbersStruct::CORE_INDEX == (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(sizeof(C2NumbersStruct) == 0, "bad size");
-
- // C2NumbersTuning: kIndex | tun | global (args)
- static_assert(C2NumbersTuning::CORE_INDEX == (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(C2NumbersTuning::PARAM_TYPE == (I::IS_FLEX_FLAG | kParamIndexNumbers | I::KIND_TUNING | I::DIR_GLOBAL), "bad index");
- static_assert(sizeof(C2NumbersTuning) == 8, "bad size");
-
- static_assert(offsetof(C2NumbersTuning, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumbersTuning, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumbersTuning, m.mNumbers) == 8, "bad offset");
-
- // C2NumbersPortTuning: kIndex | tun | port (bool, args)
- static_assert(sizeof(C2NumbersPortTuning) == 8, "bad size");
- // C2NumbersPortTuning::input: kIndex | tun | port | input (args)
- // C2NumbersPortTuning::output: kIndex | tun | port | output (args)
- static_assert(C2NumbersPortTuning::input::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(C2NumbersPortTuning::input::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers | I::KIND_TUNING | I::DIR_INPUT), "bad index");
- static_assert(C2NumbersPortTuning::output::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(C2NumbersPortTuning::output::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers | I::KIND_TUNING | I::DIR_OUTPUT), "bad index");
- static_assert(sizeof(C2NumbersPortTuning::input) == 8, "bad size");
- static_assert(sizeof(C2NumbersPortTuning::output) == 8, "bad size");
- static_assert(offsetof(C2NumbersPortTuning::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumbersPortTuning::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumbersPortTuning::input, m.mNumbers) == 8, "bad offset");
- static_assert(offsetof(C2NumbersPortTuning::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumbersPortTuning::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumbersPortTuning::output, m.mNumbers) == 8, "bad offset");
-
- // C2NumbersStreamTuning: kIndex | tun | str (bool, uint, args)
- static_assert(sizeof(C2NumbersStreamTuning) == 8, "bad size");
- // C2NumbersStreamTuning::input kIndex | tun | str | input (int, args)
- // C2NumbersStreamTuning::output kIx | tun | str | output (int, args)
- static_assert(C2NumbersStreamTuning::input::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(C2NumbersStreamTuning::input::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers | I::KIND_TUNING | I::DIR_INPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(C2NumbersStreamTuning::output::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers), "bad index");
- static_assert(C2NumbersStreamTuning::output::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexNumbers | I::KIND_TUNING | I::DIR_OUTPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(sizeof(C2NumbersStreamTuning::input) == 8, "bad size");
- static_assert(sizeof(C2NumbersStreamTuning::output) == 8, "bad size");
- static_assert(offsetof(C2NumbersStreamTuning::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumbersStreamTuning::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumbersStreamTuning::input, m.mNumbers) == 8, "bad offset");
- static_assert(offsetof(C2NumbersStreamTuning::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2NumbersStreamTuning::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2NumbersStreamTuning::output, m.mNumbers) == 8, "bad offset");
-}
-
-template<bool, unsigned ...N>
-struct _print_as_warning { };
-
-template<unsigned ...N>
-struct _print_as_warning<true, N...> : std::true_type { };
-
-#define static_assert_equals(a, b, msg) \
-static_assert(_print_as_warning<(a) == (b), a, b>::value, msg)
-
-void _C2ParamInspector::StaticFlexFromBaseTest() {
- enum { kParamIndexMy = 1203 };
- typedef C2TestBaseFlexEndSizeStruct C2MyStruct;
- typedef C2GlobalParam<C2Info, C2MyStruct, kParamIndexMy> C2MyInfo;
- typedef C2PortParam<C2Info, C2MyStruct, kParamIndexMy> C2MyPortInfo;
- typedef C2StreamParam<C2Info, C2MyStruct, kParamIndexMy> C2MyStreamInfo;
-
- typedef C2Param::Index I;
-
- // C2MyStruct has no CORE_INDEX
- //static_assert(C2MyStruct::CORE_INDEX == (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert(sizeof(C2MyStruct) == 4, "bad size");
-
- // C2MyInfo: kIndex | tun | global (args)
- static_assert_equals(C2MyInfo::CORE_INDEX, (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert_equals(C2MyInfo::PARAM_TYPE, (I::IS_FLEX_FLAG | kParamIndexMy | I::KIND_INFO | I::DIR_GLOBAL), "bad index");
- static_assert(sizeof(C2MyInfo) == 12, "bad size");
-
- static_assert(offsetof(C2MyInfo, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyInfo, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyInfo, m.signed32) == 8, "bad offset");
-
- // C2MyPortInfo: kIndex | tun | port (bool, args)
- static_assert(sizeof(C2MyPortInfo) == 12, "bad size");
- // C2MyPortInfo::input: kIndex | tun | port | input (args)
- // C2MyPortInfo::output: kIndex | tun | port | output (args)
- static_assert(C2MyPortInfo::input::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert(C2MyPortInfo::input::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexMy | I::KIND_INFO | I::DIR_INPUT), "bad index");
- static_assert(C2MyPortInfo::output::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert(C2MyPortInfo::output::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexMy | I::KIND_INFO | I::DIR_OUTPUT), "bad index");
- static_assert(sizeof(C2MyPortInfo::input) == 12, "bad size");
- static_assert(sizeof(C2MyPortInfo::output) == 12, "bad size");
- static_assert(offsetof(C2MyPortInfo::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyPortInfo::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyPortInfo::input, m.signed32) == 8, "bad offset");
- static_assert(offsetof(C2MyPortInfo::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyPortInfo::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyPortInfo::output, m.signed32) == 8, "bad offset");
-
- // C2MyStreamInfo: kIndex | tun | str (bool, uint, args)
- static_assert(sizeof(C2MyStreamInfo) == 12, "bad size");
- // C2MyStreamInfo::input kIndex | tun | str | input (int, args)
- // C2MyStreamInfo::output kIx | tun | str | output (int, args)
- static_assert(C2MyStreamInfo::input::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert(C2MyStreamInfo::input::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexMy | I::KIND_INFO | I::DIR_INPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(C2MyStreamInfo::output::CORE_INDEX ==
- (I::IS_FLEX_FLAG | kParamIndexMy), "bad index");
- static_assert(C2MyStreamInfo::output::PARAM_TYPE ==
- (I::IS_FLEX_FLAG | kParamIndexMy | I::KIND_INFO | I::DIR_OUTPUT | I::IS_STREAM_FLAG), "bad index");
- static_assert(sizeof(C2MyStreamInfo::input) == 12, "bad size");
- static_assert(sizeof(C2MyStreamInfo::output) == 12, "bad size");
- static_assert(offsetof(C2MyStreamInfo::input, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyStreamInfo::input, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyStreamInfo::input, m.signed32) == 8, "bad offset");
- static_assert(offsetof(C2MyStreamInfo::output, _mSize) == 0, "bad size");
- static_assert(offsetof(C2MyStreamInfo::output, _mIndex) == 4, "bad offset");
- static_assert(offsetof(C2MyStreamInfo::output, m.signed32) == 8, "bad offset");
-}
-
-TEST_F(C2ParamTest, ParamOpsTest) {
- const C2NumberStruct str(100);
- C2NumberStruct bstr;
-
- {
- EXPECT_EQ(100, str.mNumber);
- bstr.mNumber = 100;
-
- C2Param::CoreIndex index = C2NumberStruct::CORE_INDEX;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
- }
-
- const C2NumberTuning tun(100);
- C2NumberTuning btun;
-
- {
- C2NumberInfo inf(100);
- std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::AllocUnique(1);
-
- EXPECT_EQ(tun.coreIndex(), inf.coreIndex());
- EXPECT_NE(tun.coreIndex(), tun_->coreIndex());
- EXPECT_NE(tun.type(), inf.type());
- EXPECT_NE(tun.type(), tun_->type());
- }
-
- {
- // flags & invariables
- for (const auto &p : { tun, btun }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
- EXPECT_EQ(12u, p.size());
-
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_TRUE(p.isGlobal());
- EXPECT_FALSE(p.forInput());
- EXPECT_FALSE(p.forOutput());
- EXPECT_FALSE(p.forStream());
- EXPECT_FALSE(p.forPort());
- }
-
- // value
- EXPECT_EQ(100, tun.mNumber);
- EXPECT_EQ(0, btun.mNumber);
- EXPECT_FALSE(tun == btun);
- EXPECT_FALSE(tun.operator==(btun));
- EXPECT_TRUE(tun != btun);
- EXPECT_TRUE(tun.operator!=(btun));
- btun.mNumber = 100;
- EXPECT_EQ(tun, btun);
-
- // index
- EXPECT_EQ(C2Param::Type(tun.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(tun.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(tun.type(), C2NumberTuning::PARAM_TYPE);
- EXPECT_EQ(tun.stream(), ~0u);
-
- C2Param::CoreIndex index = C2NumberTuning::CORE_INDEX;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
-
- C2Param::Type type = C2NumberTuning::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_FALSE(type.isFlexible());
- EXPECT_TRUE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- EXPECT_EQ(C2NumberTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&tun), &tun);
- EXPECT_EQ(C2NumberPortTuning::From(&tun), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&tun), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&tun), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::From(&tun), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&tun), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&tun), nullptr);
-
- EXPECT_EQ(*(C2Param::Copy(btun)), btun);
- btun.invalidate();
- EXPECT_FALSE(C2Param::Copy(btun));
- }
-
- const C2NumberPortTuning outp1(true, 100), inp1(false, 100);
- C2NumberPortTuning boutp1, binp1, binp3(false, 100);
- const C2NumberPortTuning::input inp2(100);
- C2NumberPortTuning::input binp2;
- const C2NumberPortTuning::output outp2(100);
- C2NumberPortTuning::output boutp2;
-
- EXPECT_EQ(inp1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(outp1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(binp1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(boutp1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(inp2.coreIndex(), tun.coreIndex());
- EXPECT_EQ(outp2.coreIndex(), tun.coreIndex());
-
- EXPECT_EQ(inp1.type(), inp2.type());
- EXPECT_EQ(outp1.type(), outp2.type());
- EXPECT_NE(inp1.type(), outp1.type());
- EXPECT_NE(inp2.type(), outp2.type());
- EXPECT_NE(inp1.type(), binp1.type());
- EXPECT_NE(outp1.type(), boutp1.type());
- EXPECT_NE(inp1.type(), tun.type());
- EXPECT_NE(inp2.type(), tun.type());
-
- {
- static_assert(canCallSetPort(binp3), "should be able to");
- static_assert(canCallSetPort(binp1), "should be able to");
- static_assert(!canCallSetPort(inp1), "should not be able to (const)");
- static_assert(!canCallSetPort(inp2), "should not be able to (const & type)");
- static_assert(!canCallSetPort(binp2), "should not be able to (type)");
-
- // flags & invariables
- for (const auto &p : { outp1, inp1, boutp1 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_FALSE(p.forStream());
- EXPECT_TRUE(p.forPort());
- }
- for (const auto &p : { inp2, binp2 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_FALSE(p.forStream());
- EXPECT_TRUE(p.forPort());
- }
- for (const auto &p : { outp2, boutp2 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_FALSE(p.forStream());
- EXPECT_TRUE(p.forPort());
- }
-
- // port specific flags & invariables
- EXPECT_FALSE(outp1.forInput());
- EXPECT_TRUE(outp1.forOutput());
-
- EXPECT_TRUE(inp1.forInput());
- EXPECT_FALSE(inp1.forOutput());
-
- for (const auto &p : { outp1, inp1 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
- EXPECT_EQ(100, p.mNumber);
- }
- for (const auto &p : { outp2, boutp2 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
-
- EXPECT_FALSE(p.forInput());
- EXPECT_TRUE(p.forOutput());
- }
- for (const auto &p : { inp2, binp2 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
-
- EXPECT_TRUE(p.forInput());
- EXPECT_FALSE(p.forOutput());
- }
- for (const auto &p : { boutp1 } ) {
- EXPECT_FALSE((bool)p);
- EXPECT_TRUE(!p);
-
- EXPECT_FALSE(p.forInput());
- EXPECT_FALSE(p.forOutput());
- EXPECT_EQ(0, p.mNumber);
- }
-
- // values
- EXPECT_EQ(100, inp2.mNumber);
- EXPECT_EQ(100, outp2.mNumber);
- EXPECT_EQ(0, binp1.mNumber);
- EXPECT_EQ(0, binp2.mNumber);
- EXPECT_EQ(0, boutp1.mNumber);
- EXPECT_EQ(0, boutp2.mNumber);
-
- EXPECT_TRUE(inp1 != outp1);
- EXPECT_TRUE(inp1 == inp2);
- EXPECT_TRUE(outp1 == outp2);
- EXPECT_TRUE(binp1 == boutp1);
- EXPECT_TRUE(binp2 != boutp2);
-
- EXPECT_TRUE(inp1 != binp1);
- binp1.mNumber = 100;
- EXPECT_TRUE(inp1 != binp1);
- binp1.setPort(false /* output */);
- EXPECT_TRUE((bool)binp1);
- EXPECT_FALSE(!binp1);
- EXPECT_TRUE(inp1 == binp1);
-
- EXPECT_TRUE(inp2 != binp2);
- binp2.mNumber = 100;
- EXPECT_TRUE(inp2 == binp2);
-
- binp1.setPort(true /* output */);
- EXPECT_TRUE(outp1 == binp1);
-
- EXPECT_TRUE(outp1 != boutp1);
- boutp1.mNumber = 100;
- EXPECT_TRUE(outp1 != boutp1);
- boutp1.setPort(true /* output */);
- EXPECT_TRUE((bool)boutp1);
- EXPECT_FALSE(!boutp1);
- EXPECT_TRUE(outp1 == boutp1);
-
- EXPECT_TRUE(outp2 != boutp2);
- boutp2.mNumber = 100;
- EXPECT_TRUE(outp2 == boutp2);
-
- boutp1.setPort(false /* output */);
- EXPECT_TRUE(inp1 == boutp1);
-
- // index
- EXPECT_EQ(C2Param::Type(inp1.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(inp1.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(inp1.type(), C2NumberPortTuning::input::PARAM_TYPE);
- EXPECT_EQ(inp1.stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(inp2.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(inp2.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(inp2.type(), C2NumberPortTuning::input::PARAM_TYPE);
- EXPECT_EQ(inp2.stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(outp1.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outp1.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(outp1.type(), C2NumberPortTuning::output::PARAM_TYPE);
- EXPECT_EQ(outp1.stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(outp2.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outp2.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(outp2.type(), C2NumberPortTuning::output::PARAM_TYPE);
- EXPECT_EQ(outp2.stream(), ~0u);
-
- C2Param::CoreIndex index = C2NumberPortTuning::input::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
-
- index = C2NumberPortTuning::output::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
-
- C2Param::Type type = C2NumberPortTuning::input::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_FALSE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_TRUE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_TRUE(type.forPort());
-
- type = C2NumberPortTuning::output::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_FALSE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_TRUE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_TRUE(type.forPort());
-
- EXPECT_EQ(C2NumberPortTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&inp1), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&inp2), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&outp1), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&outp2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::From(&inp1), &inp1);
- EXPECT_EQ(C2NumberPortTuning::From(&inp2), (C2NumberPortTuning*)&inp2);
- EXPECT_EQ(C2NumberPortTuning::From(&outp1), &outp1);
- EXPECT_EQ(C2NumberPortTuning::From(&outp2), (C2NumberPortTuning*)&outp2);
- EXPECT_EQ(C2NumberPortTuning::input::From(&inp1), (C2NumberPortTuning::input*)&inp1);
- EXPECT_EQ(C2NumberPortTuning::input::From(&inp2), &inp2);
- EXPECT_EQ(C2NumberPortTuning::input::From(&outp1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&outp2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&inp1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&inp2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&outp1), (C2NumberPortTuning::output*)&outp1);
- EXPECT_EQ(C2NumberPortTuning::output::From(&outp2), &outp2);
- EXPECT_EQ(C2NumberStreamTuning::From(&inp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::From(&inp2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::From(&outp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::From(&outp2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&inp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&inp2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&outp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&outp2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&inp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&inp2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&outp1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&outp2), nullptr);
-
- EXPECT_EQ(*(C2Param::Copy(inp1)), inp1);
- EXPECT_EQ(*(C2Param::Copy(inp2)), inp2);
- EXPECT_EQ(*(C2Param::Copy(outp1)), outp1);
- EXPECT_EQ(*(C2Param::Copy(outp2)), outp2);
- }
-
- const C2NumberStreamTuning outs1(true, 1u, 100), ins1(false, 1u, 100);
- C2NumberStreamTuning bouts1, bins1, bins3(false, 1u, 100);
- const C2NumberStreamTuning::input ins2(1u, 100);
- C2NumberStreamTuning::input bins2;
- const C2NumberStreamTuning::output outs2(1u, 100);
- C2NumberStreamTuning::output bouts2;
-
- EXPECT_EQ(ins1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(outs1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(bins1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(bouts1.coreIndex(), tun.coreIndex());
- EXPECT_EQ(ins2.coreIndex(), tun.coreIndex());
- EXPECT_EQ(outs2.coreIndex(), tun.coreIndex());
-
- EXPECT_EQ(ins1.type(), ins2.type());
- EXPECT_EQ(ins1.type(), bins2.type());
- EXPECT_EQ(outs1.type(), outs2.type());
- EXPECT_EQ(outs1.type(), bouts2.type());
- EXPECT_NE(ins1.type(), outs1.type());
- EXPECT_NE(ins2.type(), outs2.type());
- EXPECT_NE(ins1.type(), bins1.type());
- EXPECT_NE(outs1.type(), bouts1.type());
- EXPECT_NE(ins1.type(), tun.type());
- EXPECT_NE(ins2.type(), tun.type());
-
- {
- static_assert(canCallSetPort(bins3), "should be able to");
- static_assert(canCallSetPort(bins1), "should be able to");
- static_assert(!canCallSetPort(ins1), "should not be able to (const)");
- static_assert(!canCallSetPort(ins2), "should not be able to (const & type)");
- static_assert(!canCallSetPort(bins2), "should not be able to (type)");
-
- // flags & invariables
- for (const auto &p : { outs1, ins1, bouts1 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_TRUE(p.forStream());
- EXPECT_FALSE(p.forPort());
- }
- for (const auto &p : { ins2, bins2 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_TRUE(p.forStream());
- EXPECT_FALSE(p.forPort());
- }
- for (const auto &p : { outs2, bouts2 }) {
- EXPECT_EQ(12u, p.size());
- EXPECT_FALSE(p.isVendor());
- EXPECT_FALSE(p.isFlexible());
- EXPECT_FALSE(p.isGlobal());
- EXPECT_TRUE(p.forStream());
- EXPECT_FALSE(p.forPort());
- }
-
- // port specific flags & invariables
- EXPECT_FALSE(outs1.forInput());
- EXPECT_TRUE(outs1.forOutput());
-
- EXPECT_TRUE(ins1.forInput());
- EXPECT_FALSE(ins1.forOutput());
-
- for (const auto &p : { outs1, ins1 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
- EXPECT_EQ(100, p.mNumber);
- EXPECT_EQ(1u, p.stream());
- }
- for (const auto &p : { outs2, bouts2 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
-
- EXPECT_FALSE(p.forInput());
- EXPECT_TRUE(p.forOutput());
- }
- for (const auto &p : { ins2, bins2 }) {
- EXPECT_TRUE((bool)p);
- EXPECT_FALSE(!p);
-
- EXPECT_TRUE(p.forInput());
- EXPECT_FALSE(p.forOutput());
- }
- for (const auto &p : { bouts1 } ) {
- EXPECT_FALSE((bool)p);
- EXPECT_TRUE(!p);
-
- EXPECT_FALSE(p.forInput());
- EXPECT_FALSE(p.forOutput());
- EXPECT_EQ(0, p.mNumber);
- }
-
- // values
- EXPECT_EQ(100, ins2.mNumber);
- EXPECT_EQ(100, outs2.mNumber);
- EXPECT_EQ(0, bins1.mNumber);
- EXPECT_EQ(0, bins2.mNumber);
- EXPECT_EQ(0, bouts1.mNumber);
- EXPECT_EQ(0, bouts2.mNumber);
-
- EXPECT_EQ(1u, ins2.stream());
- EXPECT_EQ(1u, outs2.stream());
- EXPECT_EQ(0u, bins1.stream());
- EXPECT_EQ(0u, bins2.stream());
- EXPECT_EQ(0u, bouts1.stream());
- EXPECT_EQ(0u, bouts2.stream());
-
- EXPECT_TRUE(ins1 != outs1);
- EXPECT_TRUE(ins1 == ins2);
- EXPECT_TRUE(outs1 == outs2);
- EXPECT_TRUE(bins1 == bouts1);
- EXPECT_TRUE(bins2 != bouts2);
-
- EXPECT_TRUE(ins1 != bins1);
- bins1.mNumber = 100;
- EXPECT_TRUE(ins1 != bins1);
- bins1.setPort(false /* output */);
- EXPECT_TRUE(ins1 != bins1);
- bins1.setStream(1u);
- EXPECT_TRUE(ins1 == bins1);
-
- EXPECT_TRUE(ins2 != bins2);
- bins2.mNumber = 100;
- EXPECT_TRUE(ins2 != bins2);
- bins2.setStream(1u);
- EXPECT_TRUE(ins2 == bins2);
-
- bins1.setPort(true /* output */);
- EXPECT_TRUE(outs1 == bins1);
-
- EXPECT_TRUE(outs1 != bouts1);
- bouts1.mNumber = 100;
- EXPECT_TRUE(outs1 != bouts1);
- bouts1.setPort(true /* output */);
- EXPECT_TRUE(outs1 != bouts1);
- bouts1.setStream(1u);
- EXPECT_TRUE(outs1 == bouts1);
-
- EXPECT_TRUE(outs2 != bouts2);
- bouts2.mNumber = 100;
- EXPECT_TRUE(outs2 != bouts2);
- bouts2.setStream(1u);
- EXPECT_TRUE(outs2 == bouts2);
-
- bouts1.setPort(false /* output */);
- EXPECT_TRUE(ins1 == bouts1);
-
- // index
- EXPECT_EQ(C2Param::Type(ins1.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(ins1.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(ins1.type(), C2NumberStreamTuning::input::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(ins2.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(ins2.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(ins2.type(), C2NumberStreamTuning::input::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(outs1.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outs1.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(outs1.type(), C2NumberStreamTuning::output::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(outs2.type()).coreIndex(), C2NumberStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outs2.type()).typeIndex(), kParamIndexNumber);
- EXPECT_EQ(outs2.type(), C2NumberStreamTuning::output::PARAM_TYPE);
-
- C2Param::CoreIndex index = C2NumberStreamTuning::input::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
-
- index = C2NumberStreamTuning::output::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_FALSE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumber);
-
- C2Param::Type type = C2NumberStreamTuning::input::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_FALSE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_TRUE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_TRUE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- type = C2NumberStreamTuning::output::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_FALSE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_TRUE(type.forOutput());
- EXPECT_TRUE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- EXPECT_EQ(C2NumberPortTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(nullptr), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&ins1), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&ins2), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&outs1), nullptr);
- EXPECT_EQ(C2NumberTuning::From(&outs2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::From(&ins1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::From(&ins2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::From(&outs1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::From(&outs2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&ins1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&ins2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&outs1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::input::From(&outs2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&ins1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&ins2), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&outs1), nullptr);
- EXPECT_EQ(C2NumberPortTuning::output::From(&outs2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::From(&ins1), &ins1);
- EXPECT_EQ(C2NumberStreamTuning::From(&ins2), (C2NumberStreamTuning*)&ins2);
- EXPECT_EQ(C2NumberStreamTuning::From(&outs1), &outs1);
- EXPECT_EQ(C2NumberStreamTuning::From(&outs2), (C2NumberStreamTuning*)&outs2);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&ins1), (C2NumberStreamTuning::input*)&ins1);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&ins2), &ins2);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&outs1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::input::From(&outs2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&ins1), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&ins2), nullptr);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&outs1), (C2NumberStreamTuning::output*)&outs1);
- EXPECT_EQ(C2NumberStreamTuning::output::From(&outs2), &outs2);
-
- EXPECT_EQ(*(C2Param::Copy(ins1)), ins1);
- EXPECT_EQ(*(C2Param::Copy(ins2)), ins2);
- EXPECT_EQ(*(C2Param::Copy(outs1)), outs1);
- EXPECT_EQ(*(C2Param::Copy(outs2)), outs2);
- }
-
- {
- uint32_t videoWidth[] = { 12u, C2NumberStreamTuning::output::PARAM_TYPE, 100 };
- C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
- EXPECT_NE(p1, nullptr);
- EXPECT_EQ(12u, p1->size());
- EXPECT_EQ(p1->type(), C2NumberStreamTuning::output::PARAM_TYPE);
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
- EXPECT_EQ(p1, nullptr);
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
- EXPECT_EQ(p1, nullptr);
-
- p1 = C2Param::From(videoWidth, 3);
- EXPECT_EQ(p1, nullptr);
-
- p1 = C2Param::From(videoWidth, 0);
- EXPECT_EQ(p1, nullptr);
- }
-}
-
-void StaticTestAddCoreIndex() {
- struct nobase {};
- struct base { enum : uint32_t { CORE_INDEX = 1 }; };
- static_assert(_C2AddCoreIndex<nobase, 2>::CORE_INDEX == 2, "should be 2");
- static_assert(_C2AddCoreIndex<base, 1>::CORE_INDEX == 1, "should be 1");
-}
-
-class TestFlexHelper {
- struct _Flex {
- int32_t a;
- char b[];
- _Flex() {}
- FLEX(_Flex, b);
- };
-
- struct _BoFlex {
- _Flex a;
- _BoFlex() {}
- FLEX(_BoFlex, a);
- };
-
- struct _NonFlex {
- };
-
-
- static void StaticTest() {
- static_assert(std::is_same<_C2FlexHelper<char>::FlexType, void>::value, "should be void");
- static_assert(std::is_same<_C2FlexHelper<char[]>::FlexType, char>::value, "should be char");
- static_assert(std::is_same<_C2FlexHelper<_Flex>::FlexType, char>::value, "should be char");
-
- static_assert(std::is_same<_C2FlexHelper<_BoFlex>::FlexType, char>::value, "should be void");
-
- static_assert(_C2Flexible<_Flex>::value, "should be flexible");
- static_assert(!_C2Flexible<_NonFlex>::value, "should not be flexible");
- }
-};
-
-TEST_F(C2ParamTest, FlexParamOpsTest) {
-// const C2NumbersStruct str{100};
- C2NumbersStruct bstr;
- {
-// EXPECT_EQ(100, str->m.mNumbers[0]);
- (void)&bstr.mNumbers[0];
-
- C2Param::CoreIndex index = C2NumbersStruct::CORE_INDEX;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
- }
-
- std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::AllocUnique(1);
- tun_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersTuning> tun = std::move(tun_);
- std::shared_ptr<C2NumbersTuning> btun = C2NumbersTuning::AllocShared(1);
-
- {
- // flags & invariables
- const C2NumbersTuning *T[] = { tun.get(), btun.get() };
- for (const auto p : T) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
- EXPECT_EQ(12u, p->size());
-
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_TRUE(p->isGlobal());
- EXPECT_FALSE(p->forInput());
- EXPECT_FALSE(p->forOutput());
- EXPECT_FALSE(p->forStream());
- EXPECT_FALSE(p->forPort());
- }
-
- // value
- EXPECT_EQ(100, tun->m.mNumbers[0]);
- EXPECT_EQ(0, btun->m.mNumbers[0]);
- EXPECT_FALSE(*tun == *btun);
- EXPECT_FALSE(tun->operator==(*btun));
- EXPECT_TRUE(*tun != *btun);
- EXPECT_TRUE(tun->operator!=(*btun));
- btun->m.mNumbers[0] = 100;
- EXPECT_EQ(*tun, *btun);
-
- // index
- EXPECT_EQ(C2Param::Type(tun->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(tun->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(tun->type(), C2NumbersTuning::PARAM_TYPE);
- EXPECT_EQ(tun->stream(), ~0u);
-
- C2Param::CoreIndex index = C2NumbersTuning::CORE_INDEX;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
-
- C2Param::Type type = C2NumbersTuning::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_TRUE(type.isFlexible());
- EXPECT_TRUE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- EXPECT_EQ(C2NumbersTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(tun.get()), tun.get());
- EXPECT_EQ(C2NumbersPortTuning::From(tun.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(tun.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(tun.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::From(tun.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(tun.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(tun.get()), nullptr);
-
- EXPECT_EQ(*(C2Param::Copy(*tun)), *tun);
- }
-
- std::unique_ptr<C2NumbersPortTuning> outp1_(C2NumbersPortTuning::AllocUnique(1, true)),
- inp1_ = C2NumbersPortTuning::AllocUnique(1, false);
- outp1_->m.mNumbers[0] = 100;
- inp1_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersPortTuning> outp1 = std::move(outp1_);
- std::unique_ptr<const C2NumbersPortTuning> inp1 = std::move(inp1_);
- std::shared_ptr<C2NumbersPortTuning> boutp1(C2NumbersPortTuning::AllocShared(1)),
- binp1 = C2NumbersPortTuning::AllocShared(1),
- binp3 = C2NumbersPortTuning::AllocShared(1, false);
- binp3->m.mNumbers[0] = 100;
- std::unique_ptr<C2NumbersPortTuning::input> inp2_(C2NumbersPortTuning::input::AllocUnique(1));
- inp2_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersPortTuning::input> inp2 = std::move(inp2_);
- std::shared_ptr<C2NumbersPortTuning::input> binp2(C2NumbersPortTuning::input::AllocShared(1));
- std::unique_ptr<C2NumbersPortTuning::output> outp2_(C2NumbersPortTuning::output::AllocUnique(1));
- outp2_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersPortTuning::output> outp2 = std::move(outp2_);
- std::shared_ptr<C2NumbersPortTuning::output> boutp2(C2NumbersPortTuning::output::AllocShared(1));
-
- {
- static_assert(canCallSetPort(*binp3), "should be able to");
- static_assert(canCallSetPort(*binp1), "should be able to");
- static_assert(!canCallSetPort(*inp1), "should not be able to (const)");
- static_assert(!canCallSetPort(*inp2), "should not be able to (const & type)");
- static_assert(!canCallSetPort(*binp2), "should not be able to (type)");
-
- // flags & invariables
- const C2NumbersPortTuning *P[] = { outp1.get(), inp1.get(), boutp1.get() };
- for (const auto p : P) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_FALSE(p->forStream());
- EXPECT_TRUE(p->forPort());
- }
- const C2NumbersPortTuning::input *PI[] = { inp2.get(), binp2.get() };
- for (const auto p : PI) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_FALSE(p->forStream());
- EXPECT_TRUE(p->forPort());
- }
- const C2NumbersPortTuning::output *PO[] = { outp2.get(), boutp2.get() };
- for (const auto p : PO) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_FALSE(p->forStream());
- EXPECT_TRUE(p->forPort());
- }
-
- // port specific flags & invariables
- EXPECT_FALSE(outp1->forInput());
- EXPECT_TRUE(outp1->forOutput());
-
- EXPECT_TRUE(inp1->forInput());
- EXPECT_FALSE(inp1->forOutput());
-
- const C2NumbersPortTuning *P2[] = { outp1.get(), inp1.get() };
- for (const auto p : P2) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
- EXPECT_EQ(100, p->m.mNumbers[0]);
- }
- for (const auto p : PO) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
-
- EXPECT_FALSE(p->forInput());
- EXPECT_TRUE(p->forOutput());
- }
- for (const auto p : PI) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
-
- EXPECT_TRUE(p->forInput());
- EXPECT_FALSE(p->forOutput());
- }
- const C2NumbersPortTuning *P3[] = { boutp1.get() };
- for (const auto p : P3) {
- EXPECT_FALSE((bool)(*p));
- EXPECT_TRUE(!(*p));
-
- EXPECT_FALSE(p->forInput());
- EXPECT_FALSE(p->forOutput());
- EXPECT_EQ(0, p->m.mNumbers[0]);
- }
-
- // values
- EXPECT_EQ(100, inp2->m.mNumbers[0]);
- EXPECT_EQ(100, outp2->m.mNumbers[0]);
- EXPECT_EQ(0, binp1->m.mNumbers[0]);
- EXPECT_EQ(0, binp2->m.mNumbers[0]);
- EXPECT_EQ(0, boutp1->m.mNumbers[0]);
- EXPECT_EQ(0, boutp2->m.mNumbers[0]);
-
- EXPECT_TRUE(*inp1 != *outp1);
- EXPECT_TRUE(*inp1 == *inp2);
- EXPECT_TRUE(*outp1 == *outp2);
- EXPECT_TRUE(*binp1 == *boutp1);
- EXPECT_TRUE(*binp2 != *boutp2);
-
- EXPECT_TRUE(*inp1 != *binp1);
- binp1->m.mNumbers[0] = 100;
- EXPECT_TRUE(*inp1 != *binp1);
- binp1->setPort(false /* output */);
- EXPECT_TRUE((bool)*binp1);
- EXPECT_FALSE(!*binp1);
- EXPECT_TRUE(*inp1 == *binp1);
-
- EXPECT_TRUE(*inp2 != *binp2);
- binp2->m.mNumbers[0] = 100;
- EXPECT_TRUE(*inp2 == *binp2);
-
- binp1->setPort(true /* output */);
- EXPECT_TRUE(*outp1 == *binp1);
-
- EXPECT_TRUE(*outp1 != *boutp1);
- boutp1->m.mNumbers[0] = 100;
- EXPECT_TRUE(*outp1 != *boutp1);
- boutp1->setPort(true /* output */);
- EXPECT_TRUE((bool)*boutp1);
- EXPECT_FALSE(!*boutp1);
- EXPECT_TRUE(*outp1 == *boutp1);
-
- EXPECT_TRUE(*outp2 != *boutp2);
- boutp2->m.mNumbers[0] = 100;
- EXPECT_TRUE(*outp2 == *boutp2);
-
- boutp1->setPort(false /* output */);
- EXPECT_TRUE(*inp1 == *boutp1);
-
- // index
- EXPECT_EQ(C2Param::Type(inp1->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(inp1->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(inp1->type(), C2NumbersPortTuning::input::PARAM_TYPE);
- EXPECT_EQ(inp1->stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(inp2->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(inp2->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(inp2->type(), C2NumbersPortTuning::input::PARAM_TYPE);
- EXPECT_EQ(inp2->stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(outp1->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outp1->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(outp1->type(), C2NumbersPortTuning::output::PARAM_TYPE);
- EXPECT_EQ(outp1->stream(), ~0u);
-
- EXPECT_EQ(C2Param::Type(outp2->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outp2->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(outp2->type(), C2NumbersPortTuning::output::PARAM_TYPE);
- EXPECT_EQ(outp2->stream(), ~0u);
-
- C2Param::CoreIndex index = C2NumbersPortTuning::input::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
-
- index = C2NumbersPortTuning::output::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
-
- C2Param::Type type = C2NumbersPortTuning::input::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_TRUE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_TRUE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_TRUE(type.forPort());
-
- type = C2NumbersPortTuning::output::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_TRUE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_TRUE(type.forOutput());
- EXPECT_FALSE(type.forStream());
- EXPECT_TRUE(type.forPort());
-
- EXPECT_EQ(C2NumbersPortTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(inp1.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(inp2.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(outp1.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(outp2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::From(inp1.get()), inp1.get());
- EXPECT_EQ(C2NumbersPortTuning::From(inp2.get()), (C2NumbersPortTuning*)inp2.get());
- EXPECT_EQ(C2NumbersPortTuning::From(outp1.get()), outp1.get());
- EXPECT_EQ(C2NumbersPortTuning::From(outp2.get()), (C2NumbersPortTuning*)outp2.get());
- EXPECT_EQ(C2NumbersPortTuning::input::From(inp1.get()), (C2NumbersPortTuning::input*)inp1.get());
- EXPECT_EQ(C2NumbersPortTuning::input::From(inp2.get()), inp2.get());
- EXPECT_EQ(C2NumbersPortTuning::input::From(outp1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(outp2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(inp1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(inp2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(outp1.get()), (C2NumbersPortTuning::output*)outp1.get());
- EXPECT_EQ(C2NumbersPortTuning::output::From(outp2.get()), outp2.get());
- EXPECT_EQ(C2NumbersStreamTuning::From(inp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::From(inp2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::From(outp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::From(outp2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(inp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(inp2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(outp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(outp2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(inp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(inp2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(outp1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(outp2.get()), nullptr);
-
- EXPECT_EQ(*(C2Param::Copy(*inp1)), *inp1);
- EXPECT_EQ(*(C2Param::Copy(*inp2)), *inp2);
- EXPECT_EQ(*(C2Param::Copy(*outp1)), *outp1);
- EXPECT_EQ(*(C2Param::Copy(*outp2)), *outp2);
- }
-
- std::unique_ptr<C2NumbersStreamTuning> outs1_(C2NumbersStreamTuning::AllocUnique(1, true, 1u));
- outs1_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersStreamTuning> outs1 = std::move(outs1_);
- std::unique_ptr<C2NumbersStreamTuning> ins1_(C2NumbersStreamTuning::AllocUnique(1, false, 1u));
- ins1_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersStreamTuning> ins1 = std::move(ins1_);
- std::shared_ptr<C2NumbersStreamTuning> bouts1(C2NumbersStreamTuning::AllocShared(1));
- std::shared_ptr<C2NumbersStreamTuning> bins1(C2NumbersStreamTuning::AllocShared(1));
- std::shared_ptr<C2NumbersStreamTuning> bins3(C2NumbersStreamTuning::AllocShared(1, false, 1u));
- bins3->m.mNumbers[0] = 100;
- std::unique_ptr<C2NumbersStreamTuning::input> ins2_(C2NumbersStreamTuning::input::AllocUnique(1, 1u));
- ins2_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersStreamTuning::input> ins2 = std::move(ins2_);
- std::shared_ptr<C2NumbersStreamTuning::input> bins2(C2NumbersStreamTuning::input::AllocShared(1));
- std::unique_ptr<C2NumbersStreamTuning::output> outs2_(C2NumbersStreamTuning::output::AllocUnique(1, 1u));
- outs2_->m.mNumbers[0] = 100;
- std::unique_ptr<const C2NumbersStreamTuning::output> outs2 = std::move(outs2_);
- std::shared_ptr<C2NumbersStreamTuning::output> bouts2(C2NumbersStreamTuning::output::AllocShared(1));
-
- {
- static_assert(canCallSetPort(*bins3), "should be able to");
- static_assert(canCallSetPort(*bins1), "should be able to");
- static_assert(!canCallSetPort(*ins1), "should not be able to (const)");
- static_assert(!canCallSetPort(*ins2), "should not be able to (const & type)");
- static_assert(!canCallSetPort(*bins2), "should not be able to (type)");
-
- // flags & invariables
- const C2NumbersStreamTuning *S[] = { outs1.get(), ins1.get(), bouts1.get() };
- for (const auto p : S) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_TRUE(p->forStream());
- EXPECT_FALSE(p->forPort());
- }
- const C2NumbersStreamTuning::input *SI[] = { ins2.get(), bins2.get() };
- for (const auto p : SI) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_TRUE(p->forStream());
- EXPECT_FALSE(p->forPort());
- }
- const C2NumbersStreamTuning::output *SO[] = { outs2.get(), bouts2.get() };
- for (const auto p : SO) {
- EXPECT_EQ(12u, p->size());
- EXPECT_FALSE(p->isVendor());
- EXPECT_TRUE(p->isFlexible());
- EXPECT_FALSE(p->isGlobal());
- EXPECT_TRUE(p->forStream());
- EXPECT_FALSE(p->forPort());
- }
-
- // port specific flags & invariables
- EXPECT_FALSE(outs1->forInput());
- EXPECT_TRUE(outs1->forOutput());
-
- EXPECT_TRUE(ins1->forInput());
- EXPECT_FALSE(ins1->forOutput());
-
- const C2NumbersStreamTuning *S2[] = { outs1.get(), ins1.get() };
- for (const auto p : S2) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
- EXPECT_EQ(100, p->m.mNumbers[0]);
- EXPECT_EQ(1u, p->stream());
- }
- for (const auto p : SO) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
-
- EXPECT_FALSE(p->forInput());
- EXPECT_TRUE(p->forOutput());
- }
- for (const auto p : SI) {
- EXPECT_TRUE((bool)(*p));
- EXPECT_FALSE(!(*p));
-
- EXPECT_TRUE(p->forInput());
- EXPECT_FALSE(p->forOutput());
- }
- const C2NumbersStreamTuning *S3[] = { bouts1.get() };
- for (const auto p : S3) {
- EXPECT_FALSE((bool)(*p));
- EXPECT_TRUE(!(*p));
-
- EXPECT_FALSE(p->forInput());
- EXPECT_FALSE(p->forOutput());
- EXPECT_EQ(0, p->m.mNumbers[0]);
- }
-
- // values
- EXPECT_EQ(100, ins2->m.mNumbers[0]);
- EXPECT_EQ(100, outs2->m.mNumbers[0]);
- EXPECT_EQ(0, bins1->m.mNumbers[0]);
- EXPECT_EQ(0, bins2->m.mNumbers[0]);
- EXPECT_EQ(0, bouts1->m.mNumbers[0]);
- EXPECT_EQ(0, bouts2->m.mNumbers[0]);
-
- EXPECT_EQ(1u, ins2->stream());
- EXPECT_EQ(1u, outs2->stream());
- EXPECT_EQ(0u, bins1->stream());
- EXPECT_EQ(0u, bins2->stream());
- EXPECT_EQ(0u, bouts1->stream());
- EXPECT_EQ(0u, bouts2->stream());
-
- EXPECT_TRUE(*ins1 != *outs1);
- EXPECT_TRUE(*ins1 == *ins2);
- EXPECT_TRUE(*outs1 == *outs2);
- EXPECT_TRUE(*bins1 == *bouts1);
- EXPECT_TRUE(*bins2 != *bouts2);
-
- EXPECT_TRUE(*ins1 != *bins1);
- bins1->m.mNumbers[0] = 100;
- EXPECT_TRUE(*ins1 != *bins1);
- bins1->setPort(false /* output */);
- EXPECT_TRUE(*ins1 != *bins1);
- bins1->setStream(1u);
- EXPECT_TRUE(*ins1 == *bins1);
-
- EXPECT_TRUE(*ins2 != *bins2);
- bins2->m.mNumbers[0] = 100;
- EXPECT_TRUE(*ins2 != *bins2);
- bins2->setStream(1u);
- EXPECT_TRUE(*ins2 == *bins2);
-
- bins1->setPort(true /* output */);
- EXPECT_TRUE(*outs1 == *bins1);
-
- EXPECT_TRUE(*outs1 != *bouts1);
- bouts1->m.mNumbers[0] = 100;
- EXPECT_TRUE(*outs1 != *bouts1);
- bouts1->setPort(true /* output */);
- EXPECT_TRUE(*outs1 != *bouts1);
- bouts1->setStream(1u);
- EXPECT_TRUE(*outs1 == *bouts1);
-
- EXPECT_TRUE(*outs2 != *bouts2);
- bouts2->m.mNumbers[0] = 100;
- EXPECT_TRUE(*outs2 != *bouts2);
- bouts2->setStream(1u);
- EXPECT_TRUE(*outs2 == *bouts2);
-
- bouts1->setPort(false /* output */);
- EXPECT_TRUE(*ins1 == *bouts1);
-
- // index
- EXPECT_EQ(C2Param::Type(ins1->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(ins1->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(ins1->type(), C2NumbersStreamTuning::input::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(ins2->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(ins2->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(ins2->type(), C2NumbersStreamTuning::input::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(outs1->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outs1->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(outs1->type(), C2NumbersStreamTuning::output::PARAM_TYPE);
-
- EXPECT_EQ(C2Param::Type(outs2->type()).coreIndex(), C2NumbersStruct::CORE_INDEX);
- EXPECT_EQ(C2Param::Type(outs2->type()).typeIndex(), kParamIndexNumbers);
- EXPECT_EQ(outs2->type(), C2NumbersStreamTuning::output::PARAM_TYPE);
-
- C2Param::CoreIndex index = C2NumbersStreamTuning::input::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
-
- index = C2NumbersStreamTuning::output::PARAM_TYPE;
- EXPECT_FALSE(index.isVendor());
- EXPECT_TRUE(index.isFlexible());
- EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::CoreIndex::IS_FLEX_FLAG);
- EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
-
- C2Param::Type type = C2NumbersStreamTuning::input::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_TRUE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_TRUE(type.forInput());
- EXPECT_FALSE(type.forOutput());
- EXPECT_TRUE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- type = C2NumbersStreamTuning::output::PARAM_TYPE;
- EXPECT_FALSE(type.isVendor());
- EXPECT_TRUE(type.isFlexible());
- EXPECT_FALSE(type.isGlobal());
- EXPECT_FALSE(type.forInput());
- EXPECT_TRUE(type.forOutput());
- EXPECT_TRUE(type.forStream());
- EXPECT_FALSE(type.forPort());
-
- EXPECT_EQ(C2NumbersPortTuning::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(nullptr), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(ins1.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(ins2.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(outs1.get()), nullptr);
- EXPECT_EQ(C2NumbersTuning::From(outs2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::From(ins1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::From(ins2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::From(outs1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::From(outs2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(ins1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(ins2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(outs1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::input::From(outs2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(ins1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(ins2.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(outs1.get()), nullptr);
- EXPECT_EQ(C2NumbersPortTuning::output::From(outs2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::From(ins1.get()), ins1.get());
- EXPECT_EQ(C2NumbersStreamTuning::From(ins2.get()), (C2NumbersStreamTuning*)ins2.get());
- EXPECT_EQ(C2NumbersStreamTuning::From(outs1.get()), outs1.get());
- EXPECT_EQ(C2NumbersStreamTuning::From(outs2.get()), (C2NumbersStreamTuning*)outs2.get());
- EXPECT_EQ(C2NumbersStreamTuning::input::From(ins1.get()), (C2NumbersStreamTuning::input*)ins1.get());
- EXPECT_EQ(C2NumbersStreamTuning::input::From(ins2.get()), ins2.get());
- EXPECT_EQ(C2NumbersStreamTuning::input::From(outs1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::input::From(outs2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(ins1.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(ins2.get()), nullptr);
- EXPECT_EQ(C2NumbersStreamTuning::output::From(outs1.get()), (C2NumbersStreamTuning::output*)outs1.get());
- EXPECT_EQ(C2NumbersStreamTuning::output::From(outs2.get()), outs2.get());
-
- EXPECT_EQ(*(C2Param::Copy(*ins1)), *ins1);
- EXPECT_EQ(*(C2Param::Copy(*ins2)), *ins2);
- EXPECT_EQ(*(C2Param::Copy(*outs1)), *outs1);
- EXPECT_EQ(*(C2Param::Copy(*outs2)), *outs2);
- }
-
- {
- C2Int32Value int32Value(INT32_MIN);
- static_assert(std::is_same<decltype(int32Value.value), int32_t>::value, "should be int32_t");
- EXPECT_EQ(INT32_MIN, int32Value.value);
- std::list<const C2FieldDescriptor> fields = int32Value.FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::INT32, fields.cbegin()->type());
- EXPECT_EQ(1u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
- }
-
- {
- C2Uint32Value uint32Value(UINT32_MAX);
- static_assert(std::is_same<decltype(uint32Value.value), uint32_t>::value, "should be uint32_t");
- EXPECT_EQ(UINT32_MAX, uint32Value.value);
- std::list<const C2FieldDescriptor> fields = uint32Value.FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::UINT32, fields.cbegin()->type());
- EXPECT_EQ(1u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
- }
-
- {
- C2Int64Value int64Value(INT64_MIN);
- static_assert(std::is_same<decltype(int64Value.value), int64_t>::value, "should be int64_t");
- EXPECT_EQ(INT64_MIN, int64Value.value);
- std::list<const C2FieldDescriptor> fields = int64Value.FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::INT64, fields.cbegin()->type());
- EXPECT_EQ(1u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
- }
-
- {
- C2Uint64Value uint64Value(UINT64_MAX);
- static_assert(std::is_same<decltype(uint64Value.value), uint64_t>::value, "should be uint64_t");
- EXPECT_EQ(UINT64_MAX, uint64Value.value);
- std::list<const C2FieldDescriptor> fields = uint64Value.FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::UINT64, fields.cbegin()->type());
- EXPECT_EQ(1u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
- }
-
- {
- C2FloatValue floatValue(123.4f);
- static_assert(std::is_same<decltype(floatValue.value), float>::value, "should be float");
- EXPECT_EQ(123.4f, floatValue.value);
- std::list<const C2FieldDescriptor> fields = floatValue.FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::FLOAT, fields.cbegin()->type());
- EXPECT_EQ(1u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
- }
-
- {
- uint8_t initValue[] = "ABCD";
- typedef C2GlobalParam<C2Setting, C2BlobValue, 0> BlobSetting;
- std::unique_ptr<BlobSetting> blobValue = BlobSetting::AllocUnique(6, C2ConstMemoryBlock<uint8_t>(initValue));
- static_assert(std::is_same<decltype(blobValue->m.value), uint8_t[]>::value, "should be uint8_t[]");
- EXPECT_EQ(0, memcmp(blobValue->m.value, "ABCD\0", 6));
- EXPECT_EQ(6u, blobValue->flexCount());
- std::list<const C2FieldDescriptor> fields = blobValue->FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::BLOB, fields.cbegin()->type());
- EXPECT_EQ(0u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
-
- blobValue = BlobSetting::AllocUnique(3, C2ConstMemoryBlock<uint8_t>(initValue));
- EXPECT_EQ(0, memcmp(blobValue->m.value, "ABC", 3));
- EXPECT_EQ(3u, blobValue->flexCount());
- }
-
- {
- constexpr char initValue[] = "ABCD";
- typedef C2GlobalParam<C2Setting, C2StringValue, 0> StringSetting;
- std::unique_ptr<StringSetting> stringValue = StringSetting::AllocUnique(6, C2ConstMemoryBlock<char>(initValue));
- stringValue = StringSetting::AllocUnique(6, initValue);
- static_assert(std::is_same<decltype(stringValue->m.value), char[]>::value, "should be char[]");
- EXPECT_EQ(0, memcmp(stringValue->m.value, "ABCD\0", 6));
- EXPECT_EQ(6u, stringValue->flexCount());
- std::list<const C2FieldDescriptor> fields = stringValue->FIELD_LIST;
- EXPECT_EQ(1u, fields.size());
- EXPECT_EQ(FD::STRING, fields.cbegin()->type());
- EXPECT_EQ(0u, fields.cbegin()->extent());
- EXPECT_EQ(C2String("value"), fields.cbegin()->name());
-
- stringValue = StringSetting::AllocUnique(3, C2ConstMemoryBlock<char>(initValue));
- EXPECT_EQ(0, memcmp(stringValue->m.value, "AB", 3));
- EXPECT_EQ(3u, stringValue->flexCount());
-
- stringValue = StringSetting::AllocUnique(11, "initValue");
- EXPECT_EQ(0, memcmp(stringValue->m.value, "initValue\0", 11));
- EXPECT_EQ(11u, stringValue->flexCount());
-
- stringValue = StringSetting::AllocUnique(initValue);
- EXPECT_EQ(0, memcmp(stringValue->m.value, "ABCD", 5));
- EXPECT_EQ(5u, stringValue->flexCount());
-
- stringValue = StringSetting::AllocUnique({ 'A', 'B', 'C', 'D' });
- EXPECT_EQ(0, memcmp(stringValue->m.value, "ABC", 4));
- EXPECT_EQ(4u, stringValue->flexCount());
- }
-
- {
- uint32_t videoWidth[] = { 12u, C2NumbersStreamTuning::output::PARAM_TYPE, 100 };
- C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
- EXPECT_NE(nullptr, p1);
- EXPECT_EQ(12u, p1->size());
- EXPECT_EQ(p1->type(), C2NumbersStreamTuning::output::PARAM_TYPE);
-
- C2NumbersStreamTuning::output *vst = C2NumbersStreamTuning::output::From(p1);
- EXPECT_NE(nullptr, vst);
- if (vst) {
- EXPECT_EQ(1u, vst->flexCount());
- EXPECT_EQ(100, vst->m.mNumbers[0]);
- }
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, 3);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, 0);
- EXPECT_EQ(nullptr, p1);
- }
-
- {
- uint32_t videoWidth[] = { 16u, C2NumbersPortTuning::input::PARAM_TYPE, 101, 102 };
-
- C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
- EXPECT_NE(nullptr, p1);
- EXPECT_EQ(16u, p1->size());
- EXPECT_EQ(p1->type(), C2NumbersPortTuning::input::PARAM_TYPE);
-
- C2NumbersPortTuning::input *vpt = C2NumbersPortTuning::input::From(p1);
- EXPECT_NE(nullptr, vpt);
- if (vpt) {
- EXPECT_EQ(2u, vpt->flexCount());
- EXPECT_EQ(101, vpt->m.mNumbers[0]);
- EXPECT_EQ(102, vpt->m.mNumbers[1]);
- }
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, 3);
- EXPECT_EQ(nullptr, p1);
-
- p1 = C2Param::From(videoWidth, 0);
- EXPECT_EQ(nullptr, p1);
- }
-}
-
-// ***********************
-
-#include <util/C2ParamUtils.h>
-#include <C2Config.h>
-#include <C2Component.h>
-#include <unordered_map>
-
-C2ENUM(
- MetadataType, int32_t,
- kInvalid = -1,
- kNone = 0,
- kGralloc,
- kNativeHandle,
- kANativeWindow,
- kCamera,
-)
-
-enum {
- kParamIndexVideoConfig = 0x1234,
-};
-
-struct C2VideoConfigStruct {
- int32_t width;
- uint32_t height;
- MetadataType metadataType;
- int32_t supportedFormats[];
-
- C2VideoConfigStruct() {}
-
- DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoConfig, supportedFormats)
- C2FIELD(width, "width")
- C2FIELD(height, "height")
- C2FIELD(metadataType, "metadata-type")
- C2FIELD(supportedFormats, "formats")
-};
-
-typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
-
-class MyComponentInstance : public C2ComponentInterface {
-public:
- virtual C2String getName() const override {
- /// \todo this seems too specific
- return "sample.interface";
- };
-
- virtual c2_node_id_t getId() const override {
- /// \todo how are these shared?
- return 0;
- }
-
- virtual c2_status_t config_vb(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
- (void)params;
- (void)failures;
- (void)mayBlock;
- return C2_OMITTED;
- }
-
- virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override {
- (void)targetComponent;
- return C2_OMITTED;
- }
-
- virtual c2_status_t query_vb(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
- for (C2Param* const param : stackParams) {
- (void)mayBlock;
- if (!*param) { // param is already invalid - remember it
- continue;
- }
-
- // note: this does not handle stream params (should use index...)
- if (!mMyParams.count(param->index())) {
- continue; // not my param
- }
-
- C2Param & myParam = mMyParams.find(param->index())->second;
- if (myParam.size() != param->size()) { // incorrect size
- param->invalidate();
- continue;
- }
-
- param->updateFrom(myParam);
- }
-
- for (const C2Param::Index index : heapParamIndices) {
- if (mMyParams.count(index)) {
- C2Param & myParam = mMyParams.find(index)->second;
- std::unique_ptr<C2Param> paramCopy(C2Param::Copy(myParam));
- heapParams->push_back(std::move(paramCopy));
- }
- }
-
- return C2_OK;
- }
-
- std::unordered_map<uint32_t, C2Param &> mMyParams;
-
- C2ComponentDomainInfo mDomainInfo;
-
- MyComponentInstance() {
- mMyParams.insert({mDomainInfo.index(), mDomainInfo});
- }
-
- virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override {
- (void)targetComponent;
- return C2_OMITTED;
- }
-
- class MyParamReflector : public C2ParamReflector {
- const MyComponentInstance *instance;
-
- public:
- MyParamReflector(const MyComponentInstance *i) : instance(i) { }
-
- virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override {
- switch (paramIndex.typeIndex()) {
- case decltype(instance->mDomainInfo)::CORE_INDEX:
- default:
- return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
- instance->mDomainInfo.type(),
- decltype(instance->mDomainInfo)::FIELD_LIST,
- });
- }
- return nullptr;
- }
- };
-
- virtual c2_status_t querySupportedValues_vb(
- std::vector<C2FieldSupportedValuesQuery> &fields,
- c2_blocking_t mayBlock) const override {
- (void)mayBlock;
- for (C2FieldSupportedValuesQuery &query : fields) {
- if (query.field() == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::value)) {
- query.values = C2FieldSupportedValues(
- false /* flag */,
- &mDomainInfo.value
- //,
- //{(int32_t)C2DomainVideo}
- );
- query.status = C2_OK;
- } else {
- query.status = C2_BAD_INDEX;
- }
- }
- return C2_OK;
- }
-
- std::shared_ptr<C2ParamReflector> getParamReflector() const {
- return std::shared_ptr<C2ParamReflector>(new MyParamReflector(this));
- }
-
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
- params->push_back(std::make_shared<C2ParamDescriptor>(
- true /* required */, "_domain", &mDomainInfo));
- params->push_back(std::shared_ptr<C2ParamDescriptor>(
- new C2ParamDescriptor(true /* required */, "_domain", &mDomainInfo)));
- return C2_OK;
- }
-
- virtual ~MyComponentInstance() override = default;
-};
-
-template<typename E, bool S=std::is_enum<E>::value>
-struct getter {
- int32_t get(const C2FieldSupportedValues::Primitive &p, int32_t*) {
- return p.i32;
- }
- int64_t get(const C2FieldSupportedValues::Primitive &p, int64_t*) {
- return p.i64;
- }
- uint32_t get(const C2FieldSupportedValues::Primitive &p, uint32_t*) {
- return p.u32;
- }
- uint64_t get(const C2FieldSupportedValues::Primitive &p, uint64_t*) {
- return p.u64;
- }
- float get(const C2FieldSupportedValues::Primitive &p, float*) {
- return p.fp;
- }
-};
-
-template<typename E>
-struct getter<E, true> {
- typename std::underlying_type<E>::type get(const C2FieldSupportedValues::Primitive &p, E*) {
- using u=typename std::underlying_type<E>::type;
- return getter<u>().get(p, (u*)0);
- }
-};
-
-template<typename T, bool E=std::is_enum<T>::value>
-struct lax_underlying_type {
- typedef typename std::underlying_type<T>::type type;
-};
-
-template<typename T>
-struct lax_underlying_type<T, false> {
- typedef T type;
-};
-
-template<typename E>
-typename lax_underlying_type<E>::type get(
- const C2FieldSupportedValues::Primitive &p, E*) {
- return getter<E>().get(p, (E*)0);
-}
-
-template<typename T>
-void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
- using namespace std;
- cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
- : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
- << (8 * sizeof(T));
- if (sv.type == sv.RANGE) {
- cout << ".range(" << get(sv.range.min, t);
- if (get(sv.range.step, t) != std::is_integral<T>::value) {
- cout << ":" << get(sv.range.step, t);
- }
- if (get(sv.range.num, t) != 1 || get(sv.range.denom, t) != 1) {
- cout << ":" << get(sv.range.num, t) << "/" << get(sv.range.denom, t);
- }
- cout << get(sv.range.max, t) << ")";
- }
- if (sv.values.size()) {
- cout << (sv.type == sv.FLAGS ? ".flags(" : ".list(");
- const char *sep = "";
- for (const C2FieldSupportedValues::Primitive &p : sv.values) {
- cout << sep << get(p, t);
- sep = ",";
- }
- cout << ")";
- }
- cout << endl;
-}
-
-void dumpType(C2Param::Type type) {
- using namespace std;
- cout << (type.isVendor() ? "Vendor" : "C2");
- if (type.forInput()) {
- cout << "Input";
- } else if (type.forOutput()) {
- cout << "Output";
- } else if (type.forPort() && !type.forStream()) {
- cout << "Port";
- }
- if (type.forStream()) {
- cout << "Stream";
- }
-
- if (type.isFlexible()) {
- cout << "Flex";
- }
-
- cout << type.typeIndex();
-
- switch (type.kind()) {
- case C2Param::INFO: cout << "Info"; break;
- case C2Param::SETTING: cout << "Setting"; break;
- case C2Param::TUNING: cout << "Tuning"; break;
- case C2Param::STRUCT: cout << "Struct"; break;
- default: cout << "Kind" << (int32_t)type.kind(); break;
- }
-}
-
-void dumpType(C2Param::CoreIndex type) {
- using namespace std;
- cout << (type.isVendor() ? "Vendor" : "C2");
- if (type.isFlexible()) {
- cout << "Flex";
- }
-
- cout << type.typeIndex() << "Struct";
-}
-
-void dumpType(FD::type_t type) {
- using namespace std;
- switch (type) {
- case FD::BLOB: cout << "blob "; break;
- case FD::FLOAT: cout << "float "; break;
- case FD::INT32: cout << "int32_t "; break;
- case FD::INT64: cout << "int64_t "; break;
- case FD::UINT32: cout << "uint32_t "; break;
- case FD::UINT64: cout << "uint64_t "; break;
- case FD::STRING: cout << "char "; break;
- default:
- cout << "struct ";
- dumpType((C2Param::Type)type);
- break;
- }
-}
-
-void dumpStruct(const C2StructDescriptor &sd) {
- using namespace std;
- cout << "struct ";
- dumpType(sd.coreIndex());
- cout << " {" << endl;
- //C2FieldDescriptor &f;
- for (const C2FieldDescriptor &f : sd) {
- PrintTo(f, &cout);
- cout << endl;
-
- if (f.namedValues().size()) {
- cout << ".named(";
- const char *sep = "";
- for (const FD::NamedValueType &p : f.namedValues()) {
- cout << sep << p.first << "=";
- switch (f.type()) {
- case C2Value::INT32: cout << get(p.second, (int32_t *)0); break;
- case C2Value::INT64: cout << get(p.second, (int64_t *)0); break;
- case C2Value::UINT32: cout << get(p.second, (uint32_t *)0); break;
- case C2Value::UINT64: cout << get(p.second, (uint64_t *)0); break;
- case C2Value::FLOAT: cout << get(p.second, (float *)0); break;
- default: cout << "???"; break;
- }
- sep = ",";
- }
- cout << ")";
- }
- }
-
- cout << "};" << endl;
-}
-
-void dumpDesc(const C2ParamDescriptor &pd) {
- using namespace std;
- if (pd.isRequired()) {
- cout << "required ";
- }
- if (pd.isPersistent()) {
- cout << "persistent ";
- }
- cout << "struct ";
- dumpType(C2Param::Type(pd.index().type()));
- cout << " " << pd.name() << ";" << endl;
-}
-
-TEST_F(C2ParamTest, ReflectorTest) {
- C2ComponentDomainInfo domainInfo;
- std::shared_ptr<MyComponentInstance> myComp(new MyComponentInstance);
- std::shared_ptr<C2ComponentInterface> comp = myComp;
-
- std::unique_ptr<C2StructDescriptor> desc{
- myComp->getParamReflector()->describe(C2ComponentDomainInfo::CORE_INDEX)};
- dumpStruct(*desc);
-
- std::vector<C2FieldSupportedValuesQuery> query = {
- { C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
- C2FieldSupportedValuesQuery::CURRENT },
- C2FieldSupportedValuesQuery(C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
- C2FieldSupportedValuesQuery::CURRENT),
- C2FieldSupportedValuesQuery::Current(C2ParamField(&domainInfo, &C2ComponentDomainInfo::value)),
- };
-
- EXPECT_EQ(C2_OK, comp->querySupportedValues_vb(query, C2_DONT_BLOCK));
-
- for (const C2FieldSupportedValuesQuery &q : query) {
- dumpFSV(q.values, &domainInfo.value);
- }
-}
-
-TEST_F(C2ParamTest, FieldSupportedValuesTest) {
- typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
- Uint32TestInfo t;
- std::vector<C2FieldSupportedValues> values;
- values.push_back(C2FieldSupportedValues(0, 10, 1)); // min, max, step
- values.push_back(C2FieldSupportedValues(1, 64, 2, 1)); // min, max, num, den
- values.push_back(C2FieldSupportedValues(false, {1, 2, 3})); // flags, std::initializer_list
- uint32_t val[] = {1, 3, 5, 7};
- std::vector<uint32_t> v(std::begin(val), std::end(val));
- values.push_back(C2FieldSupportedValues(false, v)); // flags, std::vector
-
- for (const C2FieldSupportedValues &sv : values) {
- dumpFSV(sv, &t.value);
- }
-}
-
-C2ENUM(Enum1, uint32_t,
- Enum1Value1,
- Enum1Value2,
- Enum1Value4 = Enum1Value2 + 2,
-);
-
-C2ENUM_CUSTOM_PREFIX(Enum2, uint32_t, "Enum",
- Enum2Value1,
- Enum2Value2,
- Enum2Value4 = Enum1Value2 + 2,
-);
-
-C2ENUM_CUSTOM_NAMES(Enum3, uint8_t,
- ({ { "value1", Enum3Value1 },
- { "value2", Enum3Value2 },
- { "value4", Enum3Value4 },
- { "invalid", Invalid } }),
- Enum3Value1,
- Enum3Value2,
- Enum3Value4 = Enum3Value2 + 2,
- Invalid,
-);
-
-TEST_F(C2ParamTest, EnumUtilsTest) {
- std::vector<std::pair<C2String, Enum3>> pairs ( { { "value1", Enum3Value1 },
- { "value2", Enum3Value2 },
- { "value4", Enum3Value4 },
- { "invalid", Invalid } });
- Enum3 e3;
- FD::namedValuesFor(e3);
-}
-
-TEST_F(C2ParamTest, ParamUtilsTest) {
- // upper case
- EXPECT_EQ("yes", C2ParamUtils::camelCaseToDashed("YES"));
- EXPECT_EQ("no", C2ParamUtils::camelCaseToDashed("NO"));
- EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YES_NO"));
- EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YES__NO"));
- EXPECT_EQ("a2dp", C2ParamUtils::camelCaseToDashed("A2DP"));
- EXPECT_EQ("mp2-ts", C2ParamUtils::camelCaseToDashed("MP2_TS"));
- EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("BLOCK_2D"));
- EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("MPEG_2_TS"));
- EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_HIDDEN_VALUE"));
- EXPECT_EQ("__hidden-value2", C2ParamUtils::camelCaseToDashed("__HIDDEN_VALUE2"));
- EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HIDDEN_VALUE_2"));
-
- // camel case
- EXPECT_EQ("yes", C2ParamUtils::camelCaseToDashed("Yes"));
- EXPECT_EQ("no", C2ParamUtils::camelCaseToDashed("No"));
- EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YesNo"));
- EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("Yes_No"));
- EXPECT_EQ("mp2-ts", C2ParamUtils::camelCaseToDashed("MP2Ts"));
- EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("Block2D"));
- EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg2ts"));
- EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_HiddenValue"));
- EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HiddenValue2"));
-
- // mixed case
- EXPECT_EQ("mp2t-s", C2ParamUtils::camelCaseToDashed("MP2T_s"));
- EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("Block_2D"));
- EXPECT_EQ("block-2-d", C2ParamUtils::camelCaseToDashed("Block2_D"));
- EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg_2ts"));
- EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg_2_TS"));
- EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_Hidden__VALUE"));
- EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HiddenValue_2"));
- EXPECT_EQ("_2", C2ParamUtils::camelCaseToDashed("_2"));
- EXPECT_EQ("__23", C2ParamUtils::camelCaseToDashed("__23"));
-}
-
-TEST_F(C2ParamTest, C2ValueTest) {
- C2Value val;
- int32_t i32 = -32;
- int64_t i64 = -64;
- uint32_t u32 = 32;
- uint64_t u64 = 64;
- float fp = 1.5f;
-
- EXPECT_EQ(C2Value::NO_INIT, val.type());
- EXPECT_EQ(false, val.get(&i32));
- EXPECT_EQ(-32, i32);
- EXPECT_EQ(false, val.get(&i64));
- EXPECT_EQ(-64, i64);
- EXPECT_EQ(false, val.get(&u32));
- EXPECT_EQ(32u, u32);
- EXPECT_EQ(false, val.get(&u64));
- EXPECT_EQ(64u, u64);
- EXPECT_EQ(false, val.get(&fp));
- EXPECT_EQ(1.5f, fp);
-
- val = int32_t(-3216);
- EXPECT_EQ(C2Value::INT32, val.type());
- EXPECT_EQ(true, val.get(&i32));
- EXPECT_EQ(-3216, i32);
- EXPECT_EQ(false, val.get(&i64));
- EXPECT_EQ(-64, i64);
- EXPECT_EQ(false, val.get(&u32));
- EXPECT_EQ(32u, u32);
- EXPECT_EQ(false, val.get(&u64));
- EXPECT_EQ(64u, u64);
- EXPECT_EQ(false, val.get(&fp));
- EXPECT_EQ(1.5f, fp);
-
- val = uint32_t(3216);
- EXPECT_EQ(C2Value::UINT32, val.type());
- EXPECT_EQ(false, val.get(&i32));
- EXPECT_EQ(-3216, i32);
- EXPECT_EQ(false, val.get(&i64));
- EXPECT_EQ(-64, i64);
- EXPECT_EQ(true, val.get(&u32));
- EXPECT_EQ(3216u, u32);
- EXPECT_EQ(false, val.get(&u64));
- EXPECT_EQ(64u, u64);
- EXPECT_EQ(false, val.get(&fp));
- EXPECT_EQ(1.5f, fp);
-
- val = int64_t(-6432);
- EXPECT_EQ(C2Value::INT64, val.type());
- EXPECT_EQ(false, val.get(&i32));
- EXPECT_EQ(-3216, i32);
- EXPECT_EQ(true, val.get(&i64));
- EXPECT_EQ(-6432, i64);
- EXPECT_EQ(false, val.get(&u32));
- EXPECT_EQ(3216u, u32);
- EXPECT_EQ(false, val.get(&u64));
- EXPECT_EQ(64u, u64);
- EXPECT_EQ(false, val.get(&fp));
- EXPECT_EQ(1.5f, fp);
-
- val = uint64_t(6432);
- EXPECT_EQ(C2Value::UINT64, val.type());
- EXPECT_EQ(false, val.get(&i32));
- EXPECT_EQ(-3216, i32);
- EXPECT_EQ(false, val.get(&i64));
- EXPECT_EQ(-6432, i64);
- EXPECT_EQ(false, val.get(&u32));
- EXPECT_EQ(3216u, u32);
- EXPECT_EQ(true, val.get(&u64));
- EXPECT_EQ(6432u, u64);
- EXPECT_EQ(false, val.get(&fp));
- EXPECT_EQ(1.5f, fp);
-
- val = 15.25f;
- EXPECT_EQ(C2Value::FLOAT, val.type());
- EXPECT_EQ(false, val.get(&i32));
- EXPECT_EQ(-3216, i32);
- EXPECT_EQ(false, val.get(&i64));
- EXPECT_EQ(-6432, i64);
- EXPECT_EQ(false, val.get(&u32));
- EXPECT_EQ(3216u, u32);
- EXPECT_EQ(false, val.get(&u64));
- EXPECT_EQ(6432u, u64);
- EXPECT_EQ(true, val.get(&fp));
- EXPECT_EQ(15.25f, fp);
-}
-
diff --git a/media/libstagefright/codec2/tests/C2_test.cpp b/media/libstagefright/codec2/tests/C2_test.cpp
deleted file mode 100644
index 46f545f..0000000
--- a/media/libstagefright/codec2/tests/C2_test.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2014 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 "C2_test"
-
-#include <gtest/gtest.h>
-
-#include <C2.h>
-
-namespace android {
-
-/* ======================================= STATIC TESTS ======================================= */
-
-template<int N>
-struct c2_const_checker
-{
- inline constexpr static int num() { return N; }
-};
-
-constexpr auto min_i32_i32 = c2_min(int32_t(1), int32_t(2));
-static_assert(std::is_same<decltype(min_i32_i32), const int32_t>::value, "should be int32_t");
-constexpr auto min_i32_i64 = c2_min(int32_t(3), int64_t(2));
-static_assert(std::is_same<decltype(min_i32_i64), const int64_t>::value, "should be int64_t");
-constexpr auto min_i8_i32 = c2_min(int8_t(0xff), int32_t(0xffffffff));
-static_assert(std::is_same<decltype(min_i8_i32), const int32_t>::value, "should be int32_t");
-
-static_assert(c2_const_checker<min_i32_i32>::num() == 1, "should be 1");
-static_assert(c2_const_checker<min_i32_i64>::num() == 2, "should be 2");
-static_assert(c2_const_checker<min_i8_i32>::num() == 0xffffffff, "should be 0xffffffff");
-
-constexpr auto min_u32_u32 = c2_min(uint32_t(1), uint32_t(2));
-static_assert(std::is_same<decltype(min_u32_u32), const uint32_t>::value, "should be uint32_t");
-constexpr auto min_u32_u64 = c2_min(uint32_t(3), uint64_t(2));
-static_assert(std::is_same<decltype(min_u32_u64), const uint32_t>::value, "should be uint32_t");
-constexpr auto min_u32_u8 = c2_min(uint32_t(0xffffffff), uint8_t(0xff));
-static_assert(std::is_same<decltype(min_u32_u8), const uint8_t>::value, "should be uint8_t");
-
-static_assert(c2_const_checker<min_u32_u32>::num() == 1, "should be 1");
-static_assert(c2_const_checker<min_u32_u64>::num() == 2, "should be 2");
-static_assert(c2_const_checker<min_u32_u8>::num() == 0xff, "should be 0xff");
-
-constexpr auto max_i32_i32 = c2_max(int32_t(1), int32_t(2));
-static_assert(std::is_same<decltype(max_i32_i32), const int32_t>::value, "should be int32_t");
-constexpr auto max_i32_i64 = c2_max(int32_t(3), int64_t(2));
-static_assert(std::is_same<decltype(max_i32_i64), const int64_t>::value, "should be int64_t");
-constexpr auto max_i8_i32 = c2_max(int8_t(0xff), int32_t(0xffffffff));
-static_assert(std::is_same<decltype(max_i8_i32), const int32_t>::value, "should be int32_t");
-
-static_assert(c2_const_checker<max_i32_i32>::num() == 2, "should be 2");
-static_assert(c2_const_checker<max_i32_i64>::num() == 3, "should be 3");
-static_assert(c2_const_checker<max_i8_i32>::num() == 0xffffffff, "should be 0xffffffff");
-
-constexpr auto max_u32_u32 = c2_max(uint32_t(1), uint32_t(2));
-static_assert(std::is_same<decltype(max_u32_u32), const uint32_t>::value, "should be uint32_t");
-constexpr auto max_u32_u64 = c2_max(uint32_t(3), uint64_t(2));
-static_assert(std::is_same<decltype(max_u32_u64), const uint64_t>::value, "should be uint64_t");
-constexpr auto max_u32_u8 = c2_max(uint32_t(0x7fffffff), uint8_t(0xff));
-static_assert(std::is_same<decltype(max_u32_u8), const uint32_t>::value, "should be uint32_t");
-
-static_assert(c2_const_checker<max_u32_u32>::num() == 2, "should be 2");
-static_assert(c2_const_checker<max_u32_u64>::num() == 3, "should be 3");
-static_assert(c2_const_checker<max_u32_u8>::num() == 0x7fffffff, "should be 0x7fffffff");
-
-/* ======================================= COUNTER TESTS ======================================= */
-
-void c2_cntr_static_test() {
- // sanity checks for construction/assignment
- constexpr c2_cntr32_t c32_a(123);
- constexpr c2_cntr64_t c64_a(-456);
- c2_cntr32_t c32_b __unused = c64_a;
- // c32_b = 64.; // DISALLOWED
- // c2_cntr64_t c64_b = c32_a; // DISALLOWED
-
- // sanity checks for some constexpr operators
- static_assert(std::is_same<decltype(c32_a + c64_a), decltype(c64_a + c32_a)>::value, "+ should result same type");
- static_assert(c32_a + c64_a == c2_cntr32_t(-333), "123 + -456 = -333");
- static_assert(c32_a + c32_a == c2_cntr32_t(246), "123 + 123 = 246");
- static_assert(c64_a + c32_a == c2_cntr32_t(-333), "-456 + 123 = 579");
- static_assert(std::is_same<decltype(c32_a + 1), decltype(1 + c32_a)>::value, "+ should result same type");
- static_assert(c32_a + 456 == c2_cntr32_t(579), "123 + 456 = 579");
- static_assert(456 + c64_a == c2_cntr64_t(0), "456 + -456 = 0");
- static_assert(std::is_same<decltype(c32_a - c64_a), decltype(c64_a - c32_a)>::value, "- should result same type");
- static_assert(c32_a - c64_a == c2_cntr32_t(579), "123 - -456 = 579");
- static_assert(c32_a - c32_a == c2_cntr32_t(0), "123 - 123 = 0");
- static_assert(c64_a - c32_a == c2_cntr32_t(-579), "-456 - 123 = -579");
- static_assert(std::is_same<decltype(c32_a - 1), decltype(1 - c32_a)>::value, "- should result same type");
- static_assert(c32_a - 456 == c2_cntr32_t(-333), "123 - 456 = -333");
- static_assert(456 - c64_a == c2_cntr64_t(912), "456 - -456 = 912");
- static_assert(std::is_same<decltype(c32_a * c64_a), decltype(c64_a * c32_a)>::value, "* should result same type");
- static_assert(c32_a * c64_a == c2_cntr32_t(-56088), "123 * -456 = -56088");
- static_assert(c32_a * c32_a == c2_cntr32_t(15129), "123 * 123 = 15129");
- static_assert(c64_a * c32_a == c2_cntr32_t(-56088), "-456 * 123 = -56088");
- static_assert(std::is_same<decltype(c32_a * 1), decltype(1 * c32_a)>::value, "* should result same type");
- static_assert(c32_a * 456 == c2_cntr32_t(56088), "123 * 456 = 56088");
- static_assert(456 * c64_a == c2_cntr64_t(-207936), "456 * -456 = -207936");
-
- static_assert((c32_a << 26u) == c2_cntr32_t(0xEC000000), "123 << 26 = 0xEC000000");
-
- // sanity checks for unary operators
- static_assert(c2_cntr32_t(1) == +c2_cntr32_t(1), "1 == +1");
- static_assert(c2_cntr32_t(1) == -c2_cntr32_t(-1), "1 == --1");
-
- // sanity checks for comparison
- using c8_t = c2_cntr_t<uint8_t>;
- static_assert(c8_t(-0x80) > c8_t(0x7f), "80 > 7F");
- static_assert(c8_t(-0x80) >= c8_t(0x7f), "80 >= 7F");
- static_assert(c8_t(0x7f) > c8_t(0x7e), "7F > 7E");
- static_assert(c8_t(0x7f) >= c8_t(0x7e), "7F >= 7E");
- static_assert(!(c8_t(-0x80) > c8_t(0)), "80 !> 00");
- static_assert(!(c8_t(-0x80) >= c8_t(0)), "80 !>= 00");
- static_assert(!(c8_t(-0x80) > c8_t(-0x80)), "80 !> 80");
- static_assert(c8_t(-0x80) >= c8_t(-0x80), "80 >= 80");
-
- static_assert(c8_t(-0x80) == c8_t(0x80), "80 == 80");
- static_assert(!(c8_t(-0x80) == c8_t(0)), "80 != 0");
- static_assert(c8_t(-0x80) != c8_t(0x7f), "80 != 7F");
- static_assert(!(c8_t(0x7f) != c8_t(0x7f)), "80 != 7F");
-
- static_assert(c8_t(0x7f) < c8_t(-0x80), "7F < 80");
- static_assert(c8_t(0x7f) <= c8_t(-0x80), "7F < 80");
- static_assert(c8_t(0x7e) < c8_t(0x7f), "7E < 7F");
- static_assert(c8_t(0x7e) <= c8_t(0x7f), "7E < 7F");
- static_assert(!(c8_t(-0x40) < c8_t(0x40)), "-40 !< 40");
- static_assert(!(c8_t(-0x40) <= c8_t(0x40)), "-40 !<= 40");
- static_assert(!(c8_t(-0x40) < c8_t(-0x40)), "-40 !< -40");
- static_assert(c8_t(-0x40) <= c8_t(-0x40), "-40 <= -40");
-
- static_assert(c2_cntr32_t(-0x7fffffff - 1) > c2_cntr32_t(0x7fffffff), "80 > 7F");
- static_assert(!(c2_cntr32_t(-0x7fffffff - 1) > c2_cntr32_t(0)), "80 !> 00");
- static_assert(c2_cntr32_t(1) == c2_cntr32_t(c2_cntr64_t(0x100000001ul)), "1 == 1");
-}
-
-class C2Test : public ::testing::Test {
-};
-
-TEST_F(C2Test, CounterTest) {
- c2_cntr32_t c32_a(123);
- c2_cntr64_t c64_a(-456);
- EXPECT_EQ(c32_a += 3, c2_cntr32_t(126));
- EXPECT_EQ(c32_a += c64_a, c2_cntr32_t(-330));
- EXPECT_EQ(c32_a <<= 2u, c2_cntr32_t(-1320));
- EXPECT_EQ(c64_a *= 3, c2_cntr64_t(-1368));
- EXPECT_EQ(c32_a -= c64_a, c2_cntr32_t(48));
- EXPECT_EQ(c32_a -= 40, c2_cntr32_t(8));
- EXPECT_EQ(c32_a *= c32_a, c2_cntr32_t(64));
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
deleted file mode 100644
index f389abc..0000000
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#include <gtest/gtest.h>
-
-#include <C2AllocatorIon.h>
-#include <C2AllocatorGralloc.h>
-#include <C2Buffer.h>
-#include <C2BufferPriv.h>
-#include <C2ParamDef.h>
-
-#include <system/graphics.h>
-
-namespace android {
-
-class C2BufferUtilsTest : public ::testing::Test {
- static void StaticSegmentTest() {
- // constructor
- static_assert(C2Segment(123u, 456u).offset == 123, "");
- static_assert(C2Segment(123u, 456u).size == 456, "");
-
- // empty
- static_assert(!C2Segment(123u, 456u).isEmpty(), "");
- static_assert(C2Segment(123u, 0u).isEmpty(), "");
-
- // valid
- static_assert(C2Segment(123u, 456u).isValid(), "");
- static_assert(C2Segment(123u, ~123u).isValid(), "");
- static_assert(!C2Segment(123u, 1 + ~123u).isValid(), "");
-
- // bool()
- static_assert(C2Segment(123u, 456u), "");
- static_assert((bool)C2Segment(123u, ~123u), "");
- static_assert(!bool(C2Segment(123u, 1 + ~123u)), "");
- static_assert(!bool(C2Segment(123u, 0)), "");
-
- // !
- static_assert(!!C2Segment(123u, 456u), "");
- static_assert(!!C2Segment(123u, ~123u), "");
- static_assert(!C2Segment(123u, 1 + ~123u), "");
- static_assert(!C2Segment(123u, 0), "");
-
- // contains
- static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 0)), "");
- static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 0)), "");
- static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, ~123u)), "");
- static_assert(!C2Segment(123u, ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
- static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
- static_assert(!C2Segment(123u, ~123u).contains(C2Segment(122u, 2u)), "");
- static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 2u)), "");
- static_assert(C2Segment(123u, 3u).contains(C2Segment(124u, 2u)), "");
- static_assert(!C2Segment(123u, 3u).contains(C2Segment(125u, 2u)), "");
-
- // ==
- static_assert(C2Segment(123u, 456u) == C2Segment(123u, 456u), "");
- static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 455u)), "");
- static_assert(!(C2Segment(123u, 456u) == C2Segment(122u, 456u)), "");
- static_assert(!(C2Segment(123u, 456u) == C2Segment(124u, 456u)), "");
- static_assert(!(C2Segment(123u, 0u) == C2Segment(124u, 0u)), "");
- static_assert(C2Segment(123u, 0u) == C2Segment(123u, 0u), "");
- static_assert(C2Segment(123u, 1 + ~123u) == C2Segment(124u, 1 + ~124u), "");
-
- // !=
- static_assert(!(C2Segment(123u, 456u) != C2Segment(123u, 456u)), "");
- static_assert(C2Segment(123u, 456u) != C2Segment(123u, 457u), "");
- static_assert(C2Segment(123u, 456u) != C2Segment(123u, 455u), "");
- static_assert(C2Segment(123u, 456u) != C2Segment(122u, 456u), "");
- static_assert(C2Segment(123u, 456u) != C2Segment(124u, 456u), "");
- static_assert(C2Segment(123u, 0u) != C2Segment(124u, 0u), "");
- static_assert(!(C2Segment(123u, 0u) != C2Segment(123u, 0u)), "");
- static_assert(!(C2Segment(123u, 1 + ~123u) != C2Segment(124u, 1 + ~124u)), "");
-
- // <=
- static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 457u), "");
- static_assert(C2Segment(123u, 456u) <= C2Segment(122u, 457u), "");
- static_assert(!(C2Segment(123u, 457u) <= C2Segment(123u, 456u)), "");
- static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 456u)), "");
- static_assert(!(C2Segment(123u, 457u) <= C2Segment(124u, 457u)), "");
- static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(122u, 0u) <= C2Segment(123u, 0u)), "");
- static_assert(C2Segment(123u, 0u) <= C2Segment(122u, 1u), "");
- static_assert(C2Segment(122u, 0u) <= C2Segment(122u, 1u), "");
- static_assert(!(C2Segment(122u, ~122u) <= C2Segment(122u, 1 + ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, 1 + ~122u)), "");
-
- // <
- static_assert(!(C2Segment(123u, 456u) < C2Segment(123u, 456u)), "");
- static_assert(C2Segment(123u, 456u) < C2Segment(123u, 457u), "");
- static_assert(C2Segment(123u, 456u) < C2Segment(122u, 457u), "");
- static_assert(!(C2Segment(123u, 457u) < C2Segment(123u, 456u)), "");
- static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 456u)), "");
- static_assert(!(C2Segment(123u, 457u) < C2Segment(124u, 457u)), "");
- static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(122u, 0u) < C2Segment(123u, 0u)), "");
- static_assert(C2Segment(123u, 0u) < C2Segment(122u, 1u), "");
- static_assert(C2Segment(122u, 0u) < C2Segment(122u, 1u), "");
- static_assert(!(C2Segment(122u, ~122u) < C2Segment(122u, 1 + ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, 1 + ~122u)), "");
-
- // <=
- static_assert(C2Segment(123u, 456u) >= C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, 457u) >= C2Segment(123u, 456u), "");
- static_assert(C2Segment(122u, 457u) >= C2Segment(123u, 456u), "");
- static_assert(!(C2Segment(123u, 456u) >= C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(123u, 456u) >= C2Segment(122u, 457u)), "");
- static_assert(!(C2Segment(124u, 457u) >= C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(123u, 457u) >= C2Segment(122u, 457u)), "");
- static_assert(!(C2Segment(123u, 0u) >= C2Segment(122u, 0u)), "");
- static_assert(C2Segment(122u, 1u) >= C2Segment(123u, 0u), "");
- static_assert(C2Segment(122u, 1u) >= C2Segment(122u, 0u), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, ~122u)), "");
- static_assert(!(C2Segment(122u, ~122u) >= C2Segment(122u, 1 + ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, 1 + ~122u)), "");
-
- // <
- static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 456u)), "");
- static_assert(C2Segment(123u, 457u) > C2Segment(123u, 456u), "");
- static_assert(C2Segment(122u, 457u) > C2Segment(123u, 456u), "");
- static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(123u, 456u) > C2Segment(122u, 457u)), "");
- static_assert(!(C2Segment(124u, 457u) > C2Segment(123u, 457u)), "");
- static_assert(!(C2Segment(123u, 457u) > C2Segment(122u, 457u)), "");
- static_assert(!(C2Segment(123u, 0u) > C2Segment(122u, 0u)), "");
- static_assert(C2Segment(122u, 1u) > C2Segment(123u, 0u), "");
- static_assert(C2Segment(122u, 1u) > C2Segment(122u, 0u), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, ~122u)), "");
- static_assert(!(C2Segment(122u, ~122u) > C2Segment(122u, 1 + ~122u)), "");
- static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, 1 + ~122u)), "");
-
- // end
- static_assert(C2Segment(123u, 456u).end() == 579u, "");
- static_assert(C2Segment(123u, 0u).end() == 123u, "");
- static_assert(C2Segment(123u, ~123u).end() == 0xffffffffu, "");
- static_assert(C2Segment(123u, 1 + ~123u).end() == 0u, "");
-
- // intersect
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 456u)) == C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 460u)) == C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(124u, 460u)) == C2Segment(124u, 455u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(579u, 460u)) == C2Segment(579u, 0u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(589u, 460u)) == C2Segment(589u, ~9u /* -10 */), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 455u)) == C2Segment(123u, 455u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(122u, 456u)) == C2Segment(123u, 455u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 123u)) == C2Segment(123u, 0u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 0u)) == C2Segment(123u, ~122u /* -123 */), "");
-
- // normalize (change invalid segments to empty segments)
- static_assert(C2Segment(123u, 456u).normalize() == C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, ~123u).normalize() == C2Segment(123u, ~123u), "");
- static_assert(C2Segment(123u, 1 + ~123u).normalize() == C2Segment(123u, 0u), "");
-
- // note: normalize cannot be used to make this work
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, ~150u)).normalize() == C2Segment(150u, 429u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() != C2Segment(150u, 429u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() == C2Segment(150u, 0u), "");
-
- // saturate (change invalid segments to full segments up to max)
- static_assert(C2Segment(123u, 456u).saturate() == C2Segment(123u, 456u), "");
- static_assert(C2Segment(123u, ~123u).saturate() == C2Segment(123u, ~123u), "");
- static_assert(C2Segment(123u, 1 + ~123u).saturate() == C2Segment(123u, ~123u), "");
-
- // note: saturate can be used to make this work but only partially
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u).saturate()).normalize() == C2Segment(150u, 429u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 100u).saturate()).normalize() == C2Segment(123u, 0u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() != C2Segment(579u, 0u), "");
- static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() == C2Segment(1000u, 0u), "");
-
- }
-
- static void StaticLinearRangeAndCapacityTest() {
- class TestCapacity : public _C2LinearCapacityAspect {
- using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
- friend class C2BufferUtilsTest;
- };
-
- class TestRange : public _C2LinearRangeAspect {
- using _C2LinearRangeAspect::_C2LinearRangeAspect;
- friend class C2BufferUtilsTest;
- };
-
- // _C2LinearCapacityAspect
- static_assert(TestCapacity(0u).capacity() == 0u, "");
- constexpr TestCapacity cap(123u);
- static_assert(TestCapacity(&cap).capacity() == 123u, "");
- static_assert(TestCapacity(nullptr).capacity() == 0u, "");
-
- // _C2LinearCapacityRange
- static_assert(TestRange(&cap).capacity() == 123u, "");
- static_assert(TestRange(&cap).offset() == 0u, "");
- static_assert(TestRange(&cap).size() == 123u, "");
- static_assert(TestRange(&cap).endOffset() == 123u, "");
-
- constexpr TestRange range(&cap, 50u, 100u);
-
- static_assert(range.capacity() == 123u, "");
- static_assert(range.offset() == 50u, "");
- static_assert(range.size() == 73u, "");
- static_assert(range.endOffset() == 123u, "");
-
- static_assert(TestRange(&cap, 20u, 30u).capacity() == 123u, "");
- static_assert(TestRange(&cap, 20u, 30u).offset() == 20u, "");
- static_assert(TestRange(&cap, 20u, 30u).size() == 30u, "");
- static_assert(TestRange(&cap, 20u, 30u).endOffset() == 50u, "");
-
- static_assert(TestRange(&cap, 200u, 30u).capacity() == 123u, "");
- static_assert(TestRange(&cap, 200u, 30u).offset() == 123u, "");
- static_assert(TestRange(&cap, 200u, 30u).size() == 0u, "");
- static_assert(TestRange(&cap, 200u, 30u).endOffset() == 123u, "");
-
- }
-
-};
-
-
-class C2BufferTest : public ::testing::Test {
-public:
- C2BufferTest()
- : mBlockPoolId(C2BlockPool::PLATFORM_START),
- mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
- mSize(0u),
- mAddr(nullptr),
- mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
- }
-
- ~C2BufferTest() = default;
-
- void allocateLinear(size_t capacity) {
- c2_status_t err = mLinearAllocator->newLinearAllocation(
- capacity,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &mLinearAllocation);
- if (err != C2_OK) {
- mLinearAllocation.reset();
- FAIL() << "C2Allocator::newLinearAllocation() failed: " << err;
- }
- }
-
- void mapLinear(size_t offset, size_t size, uint8_t **addr) {
- ASSERT_TRUE(mLinearAllocation);
- c2_status_t err = mLinearAllocation->map(
- offset,
- size,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- // TODO: fence
- nullptr,
- &mAddr);
- if (err != C2_OK) {
- mAddr = nullptr;
- FAIL() << "C2LinearAllocation::map() failed: " << err;
- }
- ASSERT_NE(nullptr, mAddr);
- mSize = size;
- *addr = (uint8_t *)mAddr;
- }
-
- void unmapLinear() {
- ASSERT_TRUE(mLinearAllocation);
- ASSERT_NE(nullptr, mAddr);
- ASSERT_NE(0u, mSize);
-
- // TODO: fence
- ASSERT_EQ(C2_OK, mLinearAllocation->unmap(mAddr, mSize, nullptr));
- mSize = 0u;
- mAddr = nullptr;
- }
-
- std::shared_ptr<C2BlockPool> makeLinearBlockPool() {
- return std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
- }
-
- void allocateGraphic(uint32_t width, uint32_t height) {
- c2_status_t err = mGraphicAllocator->newGraphicAllocation(
- width,
- height,
- HAL_PIXEL_FORMAT_YCBCR_420_888,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &mGraphicAllocation);
- if (err != C2_OK) {
- mGraphicAllocation.reset();
- FAIL() << "C2Allocator::newGraphicAllocation() failed: " << err;
- }
- }
-
- void mapGraphic(C2Rect rect, C2PlanarLayout *layout, uint8_t **addr) {
- ASSERT_TRUE(mGraphicAllocation);
- c2_status_t err = mGraphicAllocation->map(
- rect,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- // TODO: fence
- nullptr,
- layout,
- addr);
- if (err != C2_OK) {
- addr[C2PlanarLayout::PLANE_Y] = nullptr;
- addr[C2PlanarLayout::PLANE_U] = nullptr;
- addr[C2PlanarLayout::PLANE_V] = nullptr;
- FAIL() << "C2GraphicAllocation::map() failed: " << err;
- }
- mMappedRect = rect;
- memcpy(mAddrGraphic, addr, sizeof(uint8_t*) * C2PlanarLayout::MAX_NUM_PLANES);
- }
-
- void unmapGraphic() {
- ASSERT_TRUE(mGraphicAllocation);
-
- // TODO: fence
- ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(mAddrGraphic, mMappedRect, nullptr));
- }
-
- std::shared_ptr<C2BlockPool> makeGraphicBlockPool() {
- return std::make_shared<C2BasicGraphicBlockPool>(mGraphicAllocator);
- }
-
-private:
- C2BlockPool::local_id_t mBlockPoolId;
- std::shared_ptr<C2Allocator> mLinearAllocator;
- std::shared_ptr<C2LinearAllocation> mLinearAllocation;
- size_t mSize;
- void *mAddr;
- C2Rect mMappedRect;
- uint8_t* mAddrGraphic[C2PlanarLayout::MAX_NUM_PLANES];
-
- std::shared_ptr<C2Allocator> mGraphicAllocator;
- std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
-};
-
-TEST_F(C2BufferTest, LinearAllocationTest) {
- constexpr size_t kCapacity = 1024u * 1024u;
-
- allocateLinear(kCapacity);
-
- uint8_t *addr = nullptr;
- mapLinear(0u, kCapacity, &addr);
- ASSERT_NE(nullptr, addr);
-
- for (size_t i = 0; i < kCapacity; ++i) {
- addr[i] = i % 100u;
- }
-
- unmapLinear();
- addr = nullptr;
-
- mapLinear(kCapacity / 3, kCapacity / 3, &addr);
- ASSERT_NE(nullptr, addr);
- for (size_t i = 0; i < kCapacity / 3; ++i) {
- ASSERT_EQ((i + kCapacity / 3) % 100, addr[i]) << " at i = " << i;
- }
-}
-
-TEST_F(C2BufferTest, BlockPoolTest) {
- constexpr size_t kCapacity = 1024u * 1024u;
-
- std::shared_ptr<C2BlockPool> blockPool(makeLinearBlockPool());
-
- std::shared_ptr<C2LinearBlock> block;
- ASSERT_EQ(C2_OK, blockPool->fetchLinearBlock(
- kCapacity,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &block));
- ASSERT_TRUE(block);
-
- C2Acquirable<C2WriteView> writeViewHolder = block->map();
- C2WriteView writeView = writeViewHolder.get();
- ASSERT_EQ(C2_OK, writeView.error());
- ASSERT_EQ(kCapacity, writeView.capacity());
- ASSERT_EQ(0u, writeView.offset());
- ASSERT_EQ(kCapacity, writeView.size());
-
- uint8_t *data = writeView.data();
- ASSERT_NE(nullptr, data);
- for (size_t i = 0; i < writeView.size(); ++i) {
- data[i] = i % 100u;
- }
-
- writeView.setOffset(kCapacity / 3);
- data = writeView.data();
- ASSERT_NE(nullptr, data);
- for (size_t i = 0; i < writeView.size(); ++i) {
- ASSERT_EQ((i + kCapacity / 3) % 100u, data[i]) << " at i = " << i
- << "; data = " << static_cast<void *>(data);
- }
-
- C2Fence fence;
- C2ConstLinearBlock constBlock = block->share(
- kCapacity / 3, kCapacity / 3, fence);
-
- C2Acquirable<C2ReadView> readViewHolder = constBlock.map();
- C2ReadView readView = readViewHolder.get();
- ASSERT_EQ(C2_OK, readView.error());
- ASSERT_EQ(kCapacity / 3, readView.capacity());
-
- // TODO: fence
- const uint8_t *constData = readView.data();
- ASSERT_NE(nullptr, constData);
- for (size_t i = 0; i < readView.capacity(); ++i) {
- ASSERT_EQ((i + kCapacity / 3) % 100u, constData[i]) << " at i = " << i
- << "; data = " << static_cast<void *>(data)
- << "; constData = " << static_cast<const void *>(constData);
- }
-
- readView = readView.subView(333u, 100u);
- ASSERT_EQ(C2_OK, readView.error());
- ASSERT_EQ(100u, readView.capacity());
-
- constData = readView.data();
- ASSERT_NE(nullptr, constData);
- for (size_t i = 0; i < readView.capacity(); ++i) {
- ASSERT_EQ((i + 333u + kCapacity / 3) % 100u, constData[i]) << " at i = " << i;
- }
-}
-
-void fillPlane(const C2Rect rect, const C2PlaneInfo info, uint8_t *addr, uint8_t value) {
- for (uint32_t row = 0; row < rect.height / info.rowSampling; ++row) {
- int32_t rowOffset = (row + rect.top / info.rowSampling) * info.rowInc;
- for (uint32_t col = 0; col < rect.width / info.colSampling; ++col) {
- int32_t colOffset = (col + rect.left / info.colSampling) * info.colInc;
- addr[rowOffset + colOffset] = value;
- }
- }
-}
-
-bool verifyPlane(const C2Rect rect, const C2PlaneInfo info, const uint8_t *addr, uint8_t value) {
- for (uint32_t row = 0; row < rect.height / info.rowSampling; ++row) {
- int32_t rowOffset = (row + rect.top / info.rowSampling) * info.rowInc;
- for (uint32_t col = 0; col < rect.width / info.colSampling; ++col) {
- int32_t colOffset = (col + rect.left / info.colSampling) * info.colInc;
- if (addr[rowOffset + colOffset] != value) {
- return false;
- }
- }
- }
- return true;
-}
-
-TEST_F(C2BufferTest, GraphicAllocationTest) {
- constexpr uint32_t kWidth = 320;
- constexpr uint32_t kHeight = 240;
-
- allocateGraphic(kWidth, kHeight);
-
- uint8_t *addr[C2PlanarLayout::MAX_NUM_PLANES];
- C2Rect rect{ 0, 0, kWidth, kHeight };
- C2PlanarLayout layout;
- mapGraphic(rect, &layout, addr);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_Y]);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_U]);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_V]);
-
- uint8_t *y = addr[C2PlanarLayout::PLANE_Y];
- C2PlaneInfo yInfo = layout.planes[C2PlanarLayout::PLANE_Y];
- uint8_t *u = addr[C2PlanarLayout::PLANE_U];
- C2PlaneInfo uInfo = layout.planes[C2PlanarLayout::PLANE_U];
- uint8_t *v = addr[C2PlanarLayout::PLANE_V];
- C2PlaneInfo vInfo = layout.planes[C2PlanarLayout::PLANE_V];
-
- fillPlane(rect, yInfo, y, 0);
- fillPlane(rect, uInfo, u, 0);
- fillPlane(rect, vInfo, v, 0);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);
-
- unmapGraphic();
-
- mapGraphic(rect, &layout, addr);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_Y]);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_U]);
- ASSERT_NE(nullptr, addr[C2PlanarLayout::PLANE_V]);
-
- y = addr[C2PlanarLayout::PLANE_Y];
- yInfo = layout.planes[C2PlanarLayout::PLANE_Y];
- u = addr[C2PlanarLayout::PLANE_U];
- uInfo = layout.planes[C2PlanarLayout::PLANE_U];
- v = addr[C2PlanarLayout::PLANE_V];
- vInfo = layout.planes[C2PlanarLayout::PLANE_V];
-
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12));
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34));
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, y, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, u, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, v, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, y, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, u, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, v, 0));
-}
-
-TEST_F(C2BufferTest, GraphicBlockPoolTest) {
- constexpr uint32_t kWidth = 320;
- constexpr uint32_t kHeight = 240;
-
- std::shared_ptr<C2BlockPool> blockPool(makeGraphicBlockPool());
-
- std::shared_ptr<C2GraphicBlock> block;
- ASSERT_EQ(C2_OK, blockPool->fetchGraphicBlock(
- kWidth,
- kHeight,
- HAL_PIXEL_FORMAT_YCBCR_420_888,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &block));
- ASSERT_TRUE(block);
-
- C2Acquirable<C2GraphicView> graphicViewHolder = block->map();
- C2GraphicView graphicView = graphicViewHolder.get();
- ASSERT_EQ(C2_OK, graphicView.error());
- ASSERT_EQ(kWidth, graphicView.width());
- ASSERT_EQ(kHeight, graphicView.height());
-
- uint8_t *const *data = graphicView.data();
- C2PlanarLayout layout = graphicView.layout();
- ASSERT_NE(nullptr, data);
-
- uint8_t *y = data[C2PlanarLayout::PLANE_Y];
- C2PlaneInfo yInfo = layout.planes[C2PlanarLayout::PLANE_Y];
- uint8_t *u = data[C2PlanarLayout::PLANE_U];
- C2PlaneInfo uInfo = layout.planes[C2PlanarLayout::PLANE_U];
- uint8_t *v = data[C2PlanarLayout::PLANE_V];
- C2PlaneInfo vInfo = layout.planes[C2PlanarLayout::PLANE_V];
-
- fillPlane({ 0, 0, kWidth, kHeight }, yInfo, y, 0);
- fillPlane({ 0, 0, kWidth, kHeight }, uInfo, u, 0);
- fillPlane({ 0, 0, kWidth, kHeight }, vInfo, v, 0);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
- fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);
-
- C2Fence fence;
- C2ConstGraphicBlock constBlock = block->share(
- { 0, 0, kWidth, kHeight }, fence);
- block.reset();
-
- C2Acquirable<const C2GraphicView> constViewHolder = constBlock.map();
- const C2GraphicView constGraphicView = constViewHolder.get();
- ASSERT_EQ(C2_OK, constGraphicView.error());
- ASSERT_EQ(kWidth, constGraphicView.width());
- ASSERT_EQ(kHeight, constGraphicView.height());
-
- const uint8_t *const *constData = constGraphicView.data();
- layout = graphicView.layout();
- ASSERT_NE(nullptr, constData);
-
- const uint8_t *cy = constData[C2PlanarLayout::PLANE_Y];
- yInfo = layout.planes[C2PlanarLayout::PLANE_Y];
- const uint8_t *cu = constData[C2PlanarLayout::PLANE_U];
- uInfo = layout.planes[C2PlanarLayout::PLANE_U];
- const uint8_t *cv = constData[C2PlanarLayout::PLANE_V];
- vInfo = layout.planes[C2PlanarLayout::PLANE_V];
-
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, cy, 0x12));
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, cu, 0x34));
- ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, cv, 0x56));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, cy, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, cu, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, cv, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, cy, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, cu, 0));
- ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, cv, 0));
-}
-
-class BufferData : public C2BufferData {
-public:
- explicit BufferData(const std::vector<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {}
- explicit BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {}
-};
-
-class Buffer : public C2Buffer {
-public:
- explicit Buffer(const std::vector<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {}
- explicit Buffer(const std::vector<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {}
-};
-
-TEST_F(C2BufferTest, BufferDataTest) {
- std::shared_ptr<C2BlockPool> linearBlockPool(makeLinearBlockPool());
- std::shared_ptr<C2BlockPool> graphicBlockPool(makeGraphicBlockPool());
-
- constexpr uint32_t kWidth1 = 320;
- constexpr uint32_t kHeight1 = 240;
- constexpr C2Rect kCrop1(kWidth1, kHeight1);
- constexpr uint32_t kWidth2 = 176;
- constexpr uint32_t kHeight2 = 144;
- constexpr C2Rect kCrop2(kWidth2, kHeight2);
- constexpr size_t kCapacity1 = 1024u;
- constexpr size_t kCapacity2 = 2048u;
-
- std::shared_ptr<C2LinearBlock> linearBlock1;
- std::shared_ptr<C2LinearBlock> linearBlock2;
- ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock(
- kCapacity1,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &linearBlock1));
- ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock(
- kCapacity2,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &linearBlock2));
- std::shared_ptr<C2GraphicBlock> graphicBlock1;
- std::shared_ptr<C2GraphicBlock> graphicBlock2;
- ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock(
- kWidth1,
- kHeight1,
- HAL_PIXEL_FORMAT_YCBCR_420_888,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &graphicBlock1));
- ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock(
- kWidth2,
- kHeight2,
- HAL_PIXEL_FORMAT_YCBCR_420_888,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &graphicBlock2));
-
- std::shared_ptr<C2BufferData> data(new BufferData({ linearBlock1->share(0, kCapacity1, C2Fence()) }));
- EXPECT_EQ(C2BufferData::LINEAR, data->type());
- ASSERT_EQ(1u, data->linearBlocks().size());
- EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
- EXPECT_TRUE(data->graphicBlocks().empty());
-
- data.reset(new BufferData({
- linearBlock1->share(0, kCapacity1, C2Fence()),
- linearBlock2->share(0, kCapacity2, C2Fence()),
- }));
- EXPECT_EQ(C2BufferData::LINEAR_CHUNKS, data->type());
- ASSERT_EQ(2u, data->linearBlocks().size());
- EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
- EXPECT_EQ(linearBlock2->handle(), data->linearBlocks().back().handle());
- EXPECT_TRUE(data->graphicBlocks().empty());
-
- data.reset(new BufferData({ graphicBlock1->share(kCrop1, C2Fence()) }));
- EXPECT_EQ(C2BufferData::GRAPHIC, data->type());
- ASSERT_EQ(1u, data->graphicBlocks().size());
- EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
- EXPECT_TRUE(data->linearBlocks().empty());
-
- data.reset(new BufferData({
- graphicBlock1->share(kCrop1, C2Fence()),
- graphicBlock2->share(kCrop2, C2Fence()),
- }));
- EXPECT_EQ(C2BufferData::GRAPHIC_CHUNKS, data->type());
- ASSERT_EQ(2u, data->graphicBlocks().size());
- EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
- EXPECT_EQ(graphicBlock2->handle(), data->graphicBlocks().back().handle());
- EXPECT_TRUE(data->linearBlocks().empty());
-}
-
-void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
- std::function<void(void)> *cb = (std::function<void(void)> *)arg;
- (*cb)();
-}
-
-enum : uint32_t {
- kParamIndexNumber1,
- kParamIndexNumber2,
-};
-
-typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber1> C2Number1Info;
-typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber2> C2Number2Info;
-
-TEST_F(C2BufferTest, BufferTest) {
- std::shared_ptr<C2BlockPool> alloc(makeLinearBlockPool());
- constexpr size_t kCapacity = 1024u;
- std::shared_ptr<C2LinearBlock> block;
-
- ASSERT_EQ(C2_OK, alloc->fetchLinearBlock(
- kCapacity,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &block));
-
- std::atomic_bool destroyed(false);
- std::function<void(void)> arg = [&destroyed](){ destroyed = true; };
-
- std::shared_ptr<C2Buffer> buffer(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
- ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
- EXPECT_FALSE(destroyed);
- ASSERT_EQ(C2_DUPLICATE, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
- buffer.reset();
- EXPECT_TRUE(destroyed);
-
- buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
- destroyed = false;
- ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
- EXPECT_FALSE(destroyed);
- ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, nullptr));
- ASSERT_EQ(C2_OK, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg));
- EXPECT_FALSE(destroyed);
- ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg));
- buffer.reset();
- EXPECT_FALSE(destroyed);
-
- std::shared_ptr<C2Info> info1(new C2Number1Info(1));
- std::shared_ptr<C2Info> info2(new C2Number2Info(2));
- buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
- EXPECT_TRUE(buffer->info().empty());
- EXPECT_FALSE(buffer->hasInfo(info1->type()));
- EXPECT_FALSE(buffer->hasInfo(info2->type()));
-
- ASSERT_EQ(C2_OK, buffer->setInfo(info1));
- EXPECT_EQ(1u, buffer->info().size());
- EXPECT_EQ(*info1, *buffer->info().front());
- EXPECT_TRUE(buffer->hasInfo(info1->type()));
- EXPECT_FALSE(buffer->hasInfo(info2->type()));
-
- ASSERT_EQ(C2_OK, buffer->setInfo(info2));
- EXPECT_EQ(2u, buffer->info().size());
- EXPECT_TRUE(buffer->hasInfo(info1->type()));
- EXPECT_TRUE(buffer->hasInfo(info2->type()));
-
- std::shared_ptr<C2Info> removed = buffer->removeInfo(info1->type());
- ASSERT_TRUE(removed);
- EXPECT_EQ(*removed, *info1);
- EXPECT_EQ(1u, buffer->info().size());
- EXPECT_EQ(*info2, *buffer->info().front());
- EXPECT_FALSE(buffer->hasInfo(info1->type()));
- EXPECT_TRUE(buffer->hasInfo(info2->type()));
-
- removed = buffer->removeInfo(info1->type());
- ASSERT_FALSE(removed);
- EXPECT_EQ(1u, buffer->info().size());
- EXPECT_FALSE(buffer->hasInfo(info1->type()));
- EXPECT_TRUE(buffer->hasInfo(info2->type()));
-
- std::shared_ptr<C2Info> info3(new C2Number2Info(3));
- ASSERT_EQ(C2_OK, buffer->setInfo(info3));
- EXPECT_EQ(1u, buffer->info().size());
- EXPECT_FALSE(buffer->hasInfo(info1->type()));
- EXPECT_TRUE(buffer->hasInfo(info2->type()));
-
- removed = buffer->removeInfo(info2->type());
- ASSERT_TRUE(removed);
- EXPECT_EQ(*info3, *removed);
- EXPECT_TRUE(buffer->info().empty());
- EXPECT_FALSE(buffer->hasInfo(info1->type()));
- EXPECT_FALSE(buffer->hasInfo(info2->type()));
-}
-
-TEST_F(C2BufferTest, MultipleLinearMapTest) {
- std::shared_ptr<C2BlockPool> pool(makeLinearBlockPool());
- constexpr size_t kCapacity = 524288u;
- for (int i = 0; i < 100; ++i) {
- std::vector<C2WriteView> wViews;
- std::vector<C2ReadView> rViews;
- for (int j = 0; j < 16; ++j) {
- std::shared_ptr<C2LinearBlock> block;
- ASSERT_EQ(C2_OK, pool->fetchLinearBlock(
- kCapacity,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &block));
- wViews.push_back(block->map().get());
- C2ConstLinearBlock cBlock = block->share(0, kCapacity / 2, C2Fence());
- rViews.push_back(cBlock.map().get());
- }
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp b/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp
deleted file mode 100644
index 7a1374b..0000000
--- a/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <util/_C2MacroUtils.h>
-
-/** \file
- * Tests for vndk/util.
- */
-
-/* --------------------------------------- _C2MacroUtils --------------------------------------- */
-
-static_assert(0 == _C2_ARGC(), "should be 0");
-static_assert(1 == _C2_ARGC(1), "should be 1");
-static_assert(2 == _C2_ARGC(1, 2), "should be 2");
-static_assert(64 == _C2_ARGC(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64), "should be 64");
-
-static_assert(0 == _C2_ARGC(,), "should be 0");
-static_assert(1 == _C2_ARGC(1,), "should be 1");
-static_assert(2 == _C2_ARGC(1, 2,), "should be 2");
-static_assert(64 == _C2_ARGC(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,), "should be 64");
-
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
deleted file mode 100644
index 95e7c39..0000000
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ /dev/null
@@ -1,66 +0,0 @@
-cc_library_headers {
- name: "libstagefright_codec2_internal",
-
- export_include_dirs: [
- "internal",
- ],
-
- vendor_available: false,
- vndk: {
- enabled: true,
- },
-}
-
-cc_library_shared {
- name: "libstagefright_codec2_vndk",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
-
- srcs: [
- "C2AllocatorIon.cpp",
- "C2AllocatorGralloc.cpp",
- "C2Buffer.cpp",
- "C2Config.cpp",
- "C2Store.cpp",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright/codec2/include",
- "frameworks/av/media/libstagefright/codec2/vndk/internal",
- "frameworks/native/include/media/hardware",
- ],
-
- shared_libs: [
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.media.bufferpool@1.0",
- "libbinder",
- "libcutils",
- "libdl",
- "libhardware",
- "libhidlbase",
- "libion",
- "libfmq",
- "liblog",
- "libstagefright_foundation",
- "libstagefright_bufferpool@1.0",
- "libui",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-std=c++14",
- ],
-}
-
-subdirs = [
- "bufferpool",
-]
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
deleted file mode 100644
index a90e094..0000000
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright (C) 2016 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 "C2AllocatorGralloc"
-#include <utils/Log.h>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <cutils/native_handle.h>
-#include <hardware/gralloc.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-
-namespace android {
-
-namespace {
- enum : uint64_t {
- /**
- * Usage mask that is passed through from gralloc to Codec 2.0 usage.
- */
- PASSTHROUGH_USAGE_MASK =
- ~(GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_PROTECTED)
- };
-
- // verify that passthrough mask is within the platform mask
- static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
-}
-
-C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
- // gralloc does not support WRITE_PROTECTED
- return C2MemoryUsage(
- ((usage & GRALLOC_USAGE_SW_READ_MASK) ? C2MemoryUsage::CPU_READ : 0) |
- ((usage & GRALLOC_USAGE_SW_WRITE_MASK) ? C2MemoryUsage::CPU_WRITE : 0) |
- ((usage & GRALLOC_USAGE_PROTECTED) ? C2MemoryUsage::READ_PROTECTED : 0) |
- (usage & PASSTHROUGH_USAGE_MASK));
-}
-
-uint64_t C2AndroidMemoryUsage::asGrallocUsage() const {
- // gralloc does not support WRITE_PROTECTED
- return (((expected & C2MemoryUsage::CPU_READ) ? GRALLOC_USAGE_SW_READ_MASK : 0) |
- ((expected & C2MemoryUsage::CPU_WRITE) ? GRALLOC_USAGE_SW_WRITE_MASK : 0) |
- ((expected & C2MemoryUsage::READ_PROTECTED) ? GRALLOC_USAGE_PROTECTED : 0) |
- (expected & PASSTHROUGH_USAGE_MASK));
-}
-
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-
-namespace {
-
-struct BufferDescriptorInfo {
- IMapper::BufferDescriptorInfo mapperInfo;
- uint32_t stride;
-};
-
-}
-
-/* ===================================== GRALLOC ALLOCATION ==================================== */
-static c2_status_t maperr2error(Error maperr) {
- switch (maperr) {
- case Error::NONE: return C2_OK;
- case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
- case Error::BAD_BUFFER: return C2_BAD_VALUE;
- case Error::BAD_VALUE: return C2_BAD_VALUE;
- case Error::NO_RESOURCES: return C2_NO_MEMORY;
- case Error::UNSUPPORTED: return C2_CANNOT_DO;
- }
- return C2_CORRUPTED;
-}
-
-static
-bool native_handle_is_invalid(const native_handle_t *const handle) {
- // perform basic validation of a native handle
- if (handle == nullptr) {
- // null handle is considered valid
- return false;
- }
- return ((size_t)handle->version != sizeof(native_handle_t) ||
- handle->numFds < 0 ||
- handle->numInts < 0 ||
- // for sanity assume handles must occupy less memory than INT_MAX bytes
- handle->numFds > int((INT_MAX - handle->version) / sizeof(int)) - handle->numInts);
-}
-
-class C2HandleGralloc : public C2Handle {
-private:
- struct ExtraData {
- uint32_t width;
- uint32_t height;
- uint32_t format;
- uint32_t usage_lo;
- uint32_t usage_hi;
- uint32_t stride;
- uint32_t magic;
- };
-
- enum {
- NUM_INTS = sizeof(ExtraData) / sizeof(int),
- };
- const static uint32_t MAGIC = '\xc2gr\x00';
-
- static
- const ExtraData* getExtraData(const C2Handle *const handle) {
- if (handle == nullptr
- || native_handle_is_invalid(handle)
- || handle->numInts < NUM_INTS) {
- return nullptr;
- }
- return reinterpret_cast<const ExtraData*>(
- &handle->data[handle->numFds + handle->numInts - NUM_INTS]);
- }
-
- static
- ExtraData *getExtraData(C2Handle *const handle) {
- return const_cast<ExtraData *>(getExtraData(const_cast<const C2Handle *const>(handle)));
- }
-
-public:
- static bool isValid(const C2Handle *const o) {
- if (o == nullptr) { // null handle is always valid
- return true;
- }
- const ExtraData *xd = getExtraData(o);
- // we cannot validate width/height/format/usage without accessing gralloc driver
- return xd != nullptr && xd->magic == MAGIC;
- }
-
- static C2HandleGralloc* WrapNativeHandle(
- const native_handle_t *const handle,
- uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride) {
- //CHECK(handle != nullptr);
- if (native_handle_is_invalid(handle) ||
- handle->numInts > int((INT_MAX - handle->version) / sizeof(int)) - NUM_INTS - handle->numFds) {
- return nullptr;
- }
- ExtraData xd = {
- width, height, format, uint32_t(usage & 0xFFFFFFFF), uint32_t(usage >> 32),
- stride, MAGIC
- };
- native_handle_t *res = native_handle_create(handle->numFds, handle->numInts + NUM_INTS);
- if (res != nullptr) {
- memcpy(&res->data, &handle->data, sizeof(int) * (handle->numFds + handle->numInts));
- *getExtraData(res) = xd;
- }
- return reinterpret_cast<C2HandleGralloc *>(res);
- }
-
- static native_handle_t* UnwrapNativeHandle(const C2Handle *const handle) {
- const ExtraData *xd = getExtraData(handle);
- if (xd == nullptr || xd->magic != MAGIC) {
- return nullptr;
- }
- native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS);
- if (res != nullptr) {
- memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts));
- }
- return res;
- }
-
- static const C2HandleGralloc* Import(
- const C2Handle *const handle,
- uint32_t *width, uint32_t *height, uint32_t *format,
- uint64_t *usage, uint32_t *stride) {
- const ExtraData *xd = getExtraData(handle);
- if (xd == nullptr) {
- return nullptr;
- }
- *width = xd->width;
- *height = xd->height;
- *format = xd->format;
- *usage = xd->usage_lo | (uint64_t(xd->usage_hi) << 32);
- *stride = xd->stride;
-
- return reinterpret_cast<const C2HandleGralloc *>(handle);
- }
-};
-
-native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
- return C2HandleGralloc::UnwrapNativeHandle(handle);
-}
-
-C2Handle *WrapNativeCodec2GrallocHandle(
- const native_handle_t *const handle,
- uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride) {
- return C2HandleGralloc::WrapNativeHandle(handle, width, height, format, usage, stride);
-}
-
-class C2AllocationGralloc : public C2GraphicAllocation {
-public:
- virtual ~C2AllocationGralloc() override;
-
- virtual c2_status_t map(
- C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
- C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
- virtual c2_status_t unmap(
- uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override;
- virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
- virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
- virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
-
- // internal methods
- // |handle| will be moved.
- C2AllocationGralloc(
- const BufferDescriptorInfo &info,
- const sp<IMapper> &mapper,
- hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle,
- C2Allocator::id_t allocatorId);
- int dup() const;
- c2_status_t status() const;
-
-private:
- const BufferDescriptorInfo mInfo;
- const sp<IMapper> mMapper;
- const hidl_handle mHidlHandle;
- const C2HandleGralloc *mHandle;
- buffer_handle_t mBuffer;
- const C2HandleGralloc *mLockedHandle;
- bool mLocked;
- C2Allocator::id_t mAllocatorId;
-};
-
-C2AllocationGralloc::C2AllocationGralloc(
- const BufferDescriptorInfo &info,
- const sp<IMapper> &mapper,
- hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle,
- C2Allocator::id_t allocatorId)
- : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
- mInfo(info),
- mMapper(mapper),
- mHidlHandle(std::move(hidlHandle)),
- mHandle(handle),
- mBuffer(nullptr),
- mLocked(false),
- mAllocatorId(allocatorId) {
-}
-
-C2AllocationGralloc::~C2AllocationGralloc() {
- if (!mBuffer) {
- return;
- }
- if (mLocked) {
- // implementation ignores addresss and rect
- uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
- unmap(addr, C2Rect(), nullptr);
- }
- mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
-}
-
-c2_status_t C2AllocationGralloc::map(
- C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
- C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
- // TODO
- (void) fence;
- (void) usage;
-
- if (mBuffer && mLocked) {
- return C2_DUPLICATE;
- }
- if (!layout || !addr) {
- return C2_BAD_VALUE;
- }
-
- c2_status_t err = C2_OK;
- if (!mBuffer) {
- mMapper->importBuffer(
- mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- mBuffer = static_cast<buffer_handle_t>(buffer);
- }
- });
- if (err != C2_OK) {
- return err;
- }
- if (mBuffer == nullptr) {
- return C2_CORRUPTED;
- }
- mLockedHandle = C2HandleGralloc::WrapNativeHandle(
- mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height,
- (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride);
- }
-
- switch (mInfo.mapperInfo.format) {
- case PixelFormat::YCBCR_420_888:
- case PixelFormat::YV12: {
- YCbCrLayout ycbcrLayout;
- mMapper->lockYCbCr(
- const_cast<native_handle_t *>(mBuffer),
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- ycbcrLayout = mapLayout;
- }
- });
- if (err != C2_OK) {
- return err;
- }
- addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
- addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
- addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
- layout->type = C2PlanarLayout::TYPE_YUV;
- layout->numPlanes = 3;
- layout->rootPlanes = 3;
- layout->planes[C2PlanarLayout::PLANE_Y] = {
- C2PlaneInfo::CHANNEL_Y, // channel
- 1, // colInc
- (int32_t)ycbcrLayout.yStride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_U] = {
- C2PlaneInfo::CHANNEL_CB, // channel
- (int32_t)ycbcrLayout.chromaStep, // colInc
- (int32_t)ycbcrLayout.cStride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_U, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_V] = {
- C2PlaneInfo::CHANNEL_CR, // channel
- (int32_t)ycbcrLayout.chromaStep, // colInc
- (int32_t)ycbcrLayout.cStride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_V, // rootIx
- 0, // offset
- };
- // handle interleaved formats
- intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
- if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
- layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
- } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
- layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
- }
- break;
- }
-
- case PixelFormat::RGBA_8888:
- // TODO: alpha channel
- // fall-through
- case PixelFormat::RGBX_8888: {
- void *pointer = nullptr;
- mMapper->lock(
- const_cast<native_handle_t *>(mBuffer),
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- });
- if (err != C2_OK) {
- return err;
- }
- addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
- addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
- layout->type = C2PlanarLayout::TYPE_RGB;
- layout->numPlanes = 3;
- layout->rootPlanes = 1;
- layout->planes[C2PlanarLayout::PLANE_R] = {
- C2PlaneInfo::CHANNEL_R, // channel
- 4, // colInc
- 4 * (int32_t)mInfo.stride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_G] = {
- C2PlaneInfo::CHANNEL_G, // channel
- 4, // colInc
- 4 * (int32_t)mInfo.stride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 1, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_B] = {
- C2PlaneInfo::CHANNEL_B, // channel
- 4, // colInc
- 4 * (int32_t)mInfo.stride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 2, // offset
- };
- break;
- }
- default: {
- return C2_OMITTED;
- }
- }
- mLocked = true;
-
- return C2_OK;
-}
-
-c2_status_t C2AllocationGralloc::unmap(
- uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
- // TODO: check addr and size, use fence
- (void)addr;
- (void)rect;
- c2_status_t err = C2_OK;
- mMapper->unlock(
- const_cast<native_handle_t *>(mBuffer),
- [&err, &fence](const auto &maperr, const auto &releaseFence) {
- // TODO
- (void) fence;
- (void) releaseFence;
- err = maperr2error(maperr);
- if (err == C2_OK) {
- // TODO: fence
- }
- });
- if (err == C2_OK) {
- mLocked = false;
- }
- return err;
-}
-
-bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
- return other && other->handle() == handle();
-}
-
-/* ===================================== GRALLOC ALLOCATOR ==================================== */
-class C2AllocatorGralloc::Impl {
-public:
- Impl(id_t id);
-
- id_t getId() const {
- return mTraits->id;
- }
-
- C2String getName() const {
- return mTraits->name;
- }
-
- std::shared_ptr<const C2Allocator::Traits> getTraits() const {
- return mTraits;
- }
-
- c2_status_t newGraphicAllocation(
- uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
- std::shared_ptr<C2GraphicAllocation> *allocation);
-
- c2_status_t priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation);
-
- c2_status_t status() const { return mInit; }
-
-private:
- std::shared_ptr<C2Allocator::Traits> mTraits;
- c2_status_t mInit;
- sp<IAllocator> mAllocator;
- sp<IMapper> mMapper;
-};
-
-C2AllocatorGralloc::Impl::Impl(id_t id) : mInit(C2_OK) {
- // TODO: get this from allocator
- C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
- Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
- mTraits = std::make_shared<C2Allocator::Traits>(traits);
-
- // gralloc allocator is a singleton, so all objects share a global service
- mAllocator = IAllocator::getService();
- mMapper = IMapper::getService();
- if (mAllocator == nullptr || mMapper == nullptr) {
- mInit = C2_CORRUPTED;
- }
-}
-
-c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
- uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- // TODO: buffer usage should be determined according to |usage|
- (void) usage;
-
- BufferDescriptorInfo info = {
- {
- width,
- height,
- 1u, // layerCount
- (PixelFormat)format,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- },
- 0u, // stride placeholder
- };
- c2_status_t err = C2_OK;
- BufferDescriptor desc;
- mMapper->createDescriptor(
- info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- desc = descriptor;
- }
- });
- if (err != C2_OK) {
- return err;
- }
-
- // IAllocator shares IMapper error codes.
- hidl_handle buffer;
- mAllocator->allocate(
- desc,
- 1u,
- [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
- err = maperr2error(maperr);
- if (err != C2_OK) {
- return;
- }
- if (buffers.size() != 1u) {
- err = C2_CORRUPTED;
- return;
- }
- info.stride = stride;
- buffer = std::move(buffers[0]);
- });
- if (err != C2_OK) {
- return err;
- }
-
-
- allocation->reset(new C2AllocationGralloc(
- info, mMapper, buffer,
- C2HandleGralloc::WrapNativeHandle(
- buffer.getNativeHandle(),
- info.mapperInfo.width, info.mapperInfo.height,
- (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride),
- mTraits->id));
- return C2_OK;
-}
-
-c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- BufferDescriptorInfo info;
- info.mapperInfo.layerCount = 1u;
- const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
- handle,
- &info.mapperInfo.width, &info.mapperInfo.height,
- (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride);
- if (grallocHandle == nullptr) {
- return C2_BAD_VALUE;
- }
-
- hidl_handle hidlHandle = C2HandleGralloc::UnwrapNativeHandle(grallocHandle);
-
- allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
- return C2_OK;
-}
-
-C2AllocatorGralloc::C2AllocatorGralloc(id_t id) : mImpl(new Impl(id)) {}
-
-C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
-
-C2Allocator::id_t C2AllocatorGralloc::getId() const {
- return mImpl->getId();
-}
-
-C2String C2AllocatorGralloc::getName() const {
- return mImpl->getName();
-}
-
-std::shared_ptr<const C2Allocator::Traits> C2AllocatorGralloc::getTraits() const {
- return mImpl->getTraits();
-}
-
-c2_status_t C2AllocatorGralloc::newGraphicAllocation(
- uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- return mImpl->newGraphicAllocation(width, height, format, usage, allocation);
-}
-
-c2_status_t C2AllocatorGralloc::priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- return mImpl->priorGraphicAllocation(handle, allocation);
-}
-
-c2_status_t C2AllocatorGralloc::status() const {
- return mImpl->status();
-}
-
-bool C2AllocatorGralloc::isValid(const C2Handle* const o) {
- return C2HandleGralloc::isValid(o);
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
deleted file mode 100644
index 664c09e..0000000
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2016 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 "C2AllocatorIon"
-#include <utils/Log.h>
-
-#include <list>
-
-#include <ion/ion.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <C2AllocatorIon.h>
-#include <C2Buffer.h>
-#include <C2ErrnoUtils.h>
-
-namespace android {
-
-/* size_t <=> int(lo), int(hi) conversions */
-constexpr inline int size2intLo(size_t s) {
- return int(s & 0xFFFFFFFF);
-}
-
-constexpr inline int size2intHi(size_t s) {
- // cast to uint64_t as size_t may be 32 bits wide
- return int((uint64_t(s) >> 32) & 0xFFFFFFFF);
-}
-
-constexpr inline size_t ints2size(int intLo, int intHi) {
- // convert in 2 stages to 64 bits as intHi may be negative
- return size_t(unsigned(intLo)) | size_t(uint64_t(unsigned(intHi)) << 32);
-}
-
-/* ========================================= ION HANDLE ======================================== */
-/**
- * ION handle
- *
- * There can be only a sole ion client per process, this is captured in the ion fd that is passed
- * to the constructor, but this should be managed by the ion buffer allocator/mapper.
- *
- * ion uses ion_user_handle_t for buffers. We don't store this in the native handle as
- * it requires an ion_free to decref. Instead, we share the buffer to get an fd that also holds
- * a refcount.
- *
- * This handle will not capture mapped fd-s as updating that would require a global mutex.
- */
-
-struct C2HandleIon : public C2Handle {
- // ion handle owns ionFd(!) and bufferFd
- C2HandleIon(int bufferFd, size_t size)
- : C2Handle(cHeader),
- mFds{ bufferFd },
- mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
-
- static bool isValid(const C2Handle * const o);
-
- int bufferFd() const { return mFds.mBuffer; }
- size_t size() const {
- return size_t(unsigned(mInts.mSizeLo))
- | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
- }
-
-protected:
- struct {
- int mBuffer; // shared ion buffer
- } mFds;
- struct {
- int mSizeLo; // low 32-bits of size
- int mSizeHi; // high 32-bits of size
- int mMagic;
- } mInts;
-
-private:
- typedef C2HandleIon _type;
- enum {
- kMagic = '\xc2io\x00',
- numFds = sizeof(mFds) / sizeof(int),
- numInts = sizeof(mInts) / sizeof(int),
- version = sizeof(C2Handle)
- };
- //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
- const static C2Handle cHeader;
-};
-
-const C2Handle C2HandleIon::cHeader = {
- C2HandleIon::version,
- C2HandleIon::numFds,
- C2HandleIon::numInts,
- {}
-};
-
-// static
-bool C2HandleIon::isValid(const C2Handle * const o) {
- if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
- return false;
- }
- const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
- return other->mInts.mMagic == kMagic;
-}
-
-// TODO: is the dup of an ion fd identical to ion_share?
-
-/* ======================================= ION ALLOCATION ====================================== */
-class C2AllocationIon : public C2LinearAllocation {
-public:
- /* Interface methods */
- virtual c2_status_t map(
- size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence,
- void **addr /* nonnull */) override;
- virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fenceFd) override;
- virtual ~C2AllocationIon() override;
- virtual const C2Handle *handle() const override;
- virtual id_t getAllocatorId() const override;
- virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
-
- // internal methods
- C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
- C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
-
- c2_status_t status() const;
-
-protected:
- class Impl;
- Impl *mImpl;
-
- // TODO: we could make this encapsulate shared_ptr and copiable
- C2_DO_NOT_COPY(C2AllocationIon);
-};
-
-class C2AllocationIon::Impl {
-private:
- /**
- * Constructs an ion allocation.
- *
- * \note We always create an ion allocation, even if the allocation or import fails
- * so that we can capture the error.
- *
- * \param ionFd ion client (ownership transferred to created object)
- * \param owned whehter native_handle_t is owned by an allocation or not.
- * \param capacity size of allocation
- * \param bufferFd buffer handle (ownership transferred to created object). Must be
- * invalid if err is not 0.
- * \param buffer ion buffer user handle (ownership transferred to created object). Must be
- * invalid if err is not 0.
- * \param err errno during buffer allocation or import
- */
- Impl(int ionFd, bool owned, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
- : mIonFd(ionFd),
- mHandleOwned(owned),
- mHandle(bufferFd, capacity),
- mBuffer(buffer),
- mId(id),
- mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
- mMapFd(-1) {
- if (mInit != C2_OK) {
- // close ionFd now on error
- if (mIonFd >= 0) {
- close(mIonFd);
- mIonFd = -1;
- }
- // C2_CHECK(bufferFd < 0);
- // C2_CHECK(buffer < 0);
- }
- }
-
-public:
- /**
- * Constructs an ion allocation by importing a shared buffer fd.
- *
- * \param ionFd ion client (ownership transferred to created object)
- * \param capacity size of allocation
- * \param bufferFd buffer handle (ownership transferred to created object)
- *
- * \return created ion allocation (implementation) which may be invalid if the
- * import failed.
- */
- static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
- ion_user_handle_t buffer = -1;
- int ret = ion_import(ionFd, bufferFd, &buffer);
- return new Impl(ionFd, false, capacity, bufferFd, buffer, id, ret);
- }
-
- /**
- * Constructs an ion allocation by allocating an ion buffer.
- *
- * \param ionFd ion client (ownership transferred to created object)
- * \param size size of allocation
- * \param align desired alignment of allocation
- * \param heapMask mask of heaps considered
- * \param flags ion allocation flags
- *
- * \return created ion allocation (implementation) which may be invalid if the
- * allocation failed.
- */
- static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
- int bufferFd = -1;
- ion_user_handle_t buffer = -1;
- int ret = ion_alloc(ionFd, size, align, heapMask, flags, &buffer);
- if (ret == 0) {
- // get buffer fd for native handle constructor
- ret = ion_share(ionFd, buffer, &bufferFd);
- if (ret != 0) {
- ion_free(ionFd, buffer);
- buffer = -1;
- }
- }
- return new Impl(ionFd, true, size, bufferFd, buffer, id, ret);
- }
-
- c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
- (void)fence; // TODO: wait for fence
- *addr = nullptr;
- if (!mMappings.empty()) {
- ALOGV("multiple map");
- // TODO: technically we should return DUPLICATE here, but our block views don't
- // actually unmap, so we end up remapping an ion buffer multiple times.
- //
- // return C2_DUPLICATE;
- }
- if (size == 0) {
- return C2_BAD_VALUE;
- }
-
- int prot = PROT_NONE;
- int flags = MAP_PRIVATE;
- if (usage.expected & C2MemoryUsage::CPU_READ) {
- prot |= PROT_READ;
- }
- if (usage.expected & C2MemoryUsage::CPU_WRITE) {
- prot |= PROT_WRITE;
- flags = MAP_SHARED;
- }
-
- size_t alignmentBytes = offset % PAGE_SIZE;
- size_t mapOffset = offset - alignmentBytes;
- size_t mapSize = size + alignmentBytes;
- Mapping map = { nullptr, alignmentBytes, mapSize };
-
- c2_status_t err = C2_OK;
- if (mMapFd == -1) {
- int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
- flags, mapOffset, (unsigned char**)&map.addr, &mMapFd);
- if (ret) {
- mMapFd = -1;
- map.addr = *addr = nullptr;
- err = c2_map_errno<EINVAL>(-ret);
- } else {
- *addr = (uint8_t *)map.addr + alignmentBytes;
- }
- } else {
- map.addr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
- if (map.addr == MAP_FAILED) {
- map.addr = *addr = nullptr;
- err = c2_map_errno<EINVAL>(errno);
- } else {
- *addr = (uint8_t *)map.addr + alignmentBytes;
- }
- }
- if (map.addr) {
- mMappings.push_back(map);
- }
- return err;
- }
-
- c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
- if (mMapFd < 0 || mMappings.empty()) {
- return C2_NOT_FOUND;
- }
- for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
- if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
- size + it->alignmentBytes != it->size) {
- continue;
- }
- int err = munmap(it->addr, it->size);
- if (err != 0) {
- return c2_map_errno<EINVAL>(errno);
- }
- if (fence) {
- *fence = C2Fence(); // not using fences
- }
- (void)mMappings.erase(it);
- return C2_OK;
- }
- return C2_BAD_VALUE;
- }
-
- ~Impl() {
- if (!mMappings.empty()) {
- ALOGD("Dangling mappings!");
- for (const Mapping &map : mMappings) {
- (void)munmap(map.addr, map.size);
- }
- }
- if (mMapFd >= 0) {
- close(mMapFd);
- mMapFd = -1;
- }
- if (mInit == C2_OK) {
- (void)ion_free(mIonFd, mBuffer);
- }
- if (mIonFd >= 0) {
- close(mIonFd);
- }
- if (mHandleOwned) {
- native_handle_close(&mHandle);
- }
- }
-
- c2_status_t status() const {
- return mInit;
- }
-
- const C2Handle *handle() const {
- return &mHandle;
- }
-
- C2Allocator::id_t getAllocatorId() const {
- return mId;
- }
-
- ion_user_handle_t ionHandle() const {
- return mBuffer;
- }
-
-private:
- int mIonFd;
- bool mHandleOwned;
- C2HandleIon mHandle;
- ion_user_handle_t mBuffer;
- C2Allocator::id_t mId;
- c2_status_t mInit;
- int mMapFd; // only one for now
- struct Mapping {
- void *addr;
- size_t alignmentBytes;
- size_t size;
- };
- std::list<Mapping> mMappings;
-};
-
-c2_status_t C2AllocationIon::map(
- size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
- return mImpl->map(offset, size, usage, fence, addr);
-}
-
-c2_status_t C2AllocationIon::unmap(void *addr, size_t size, C2Fence *fence) {
- return mImpl->unmap(addr, size, fence);
-}
-
-c2_status_t C2AllocationIon::status() const {
- return mImpl->status();
-}
-
-C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
- return mImpl->getAllocatorId();
-}
-
-bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
- if (!other || other->getAllocatorId() != getAllocatorId()) {
- return false;
- }
- // get user handle to compare objects
- std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
- return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
-}
-
-const C2Handle *C2AllocationIon::handle() const {
- return mImpl->handle();
-}
-
-C2AllocationIon::~C2AllocationIon() {
- delete mImpl;
-}
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
- unsigned heapMask, unsigned flags, C2Allocator::id_t id)
- : C2LinearAllocation(size),
- mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
- : C2LinearAllocation(size),
- mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
-
-/* ======================================= ION ALLOCATOR ====================================== */
-C2AllocatorIon::C2AllocatorIon(id_t id)
- : mInit(C2_OK),
- mIonFd(ion_open()) {
- if (mIonFd < 0) {
- switch (errno) {
- case ENOENT: mInit = C2_OMITTED; break;
- default: mInit = c2_map_errno<EACCES>(errno); break;
- }
- } else {
- C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
- Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
- mTraits = std::make_shared<Traits>(traits);
- }
-}
-
-C2AllocatorIon::~C2AllocatorIon() {
- if (mInit == C2_OK) {
- ion_close(mIonFd);
- }
-}
-
-C2Allocator::id_t C2AllocatorIon::getId() const {
- return mTraits->id;
-}
-
-C2String C2AllocatorIon::getName() const {
- return mTraits->name;
-}
-
-std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
- return mTraits;
-}
-
-c2_status_t C2AllocatorIon::newLinearAllocation(
- uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
- if (allocation == nullptr) {
- return C2_BAD_VALUE;
- }
-
- allocation->reset();
- if (mInit != C2_OK) {
- return mInit;
- }
-
- // get align, heapMask and flags
- //size_t align = 1;
- size_t align = 0;
- unsigned heapMask = ~0;
- unsigned flags = 0;
- //TODO
- (void) usage;
-#if 0
- int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
- if (err < 0) {
- return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
- }
-#endif
-
- std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
- c2_status_t ret = alloc->status();
- if (ret == C2_OK) {
- *allocation = alloc;
- }
- return ret;
-}
-
-c2_status_t C2AllocatorIon::priorLinearAllocation(
- const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
- *allocation = nullptr;
- if (mInit != C2_OK) {
- return mInit;
- }
-
- if (!C2HandleIon::isValid(handle)) {
- return C2_BAD_VALUE;
- }
-
- // TODO: get capacity and validate it
- const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
- std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
- c2_status_t ret = alloc->status();
- if (ret == C2_OK) {
- *allocation = alloc;
- }
- return ret;
-}
-
-bool C2AllocatorIon::isValid(const C2Handle* const o) {
- return C2HandleIon::isValid(o);
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
deleted file mode 100644
index af2c20d..0000000
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * Copyright (C) 2016 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 "C2Buffer"
-#include <utils/Log.h>
-
-#include <list>
-#include <map>
-#include <mutex>
-
-#include <C2BufferPriv.h>
-#include <C2BlockInternal.h>
-
-#include <ClientManager.h>
-
-namespace {
-
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocation;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocator;
-using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
-
-// This anonymous namespace contains the helper classes that allow our implementation to create
-// block/buffer objects.
-//
-// Inherit from the parent, share with the friend.
-class ReadViewBuddy : public C2ReadView {
- using C2ReadView::C2ReadView;
- friend class ::C2ConstLinearBlock;
-};
-
-class WriteViewBuddy : public C2WriteView {
- using C2WriteView::C2WriteView;
- friend class ::C2LinearBlock;
-};
-
-class ConstLinearBlockBuddy : public C2ConstLinearBlock {
- using C2ConstLinearBlock::C2ConstLinearBlock;
- friend class ::C2LinearBlock;
-};
-
-class LinearBlockBuddy : public C2LinearBlock {
- using C2LinearBlock::C2LinearBlock;
- friend class ::C2BasicLinearBlockPool;
-};
-
-class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
- using C2Acquirable::C2Acquirable;
- friend class ::C2ConstLinearBlock;
-};
-
-class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
- using C2Acquirable::C2Acquirable;
- friend class ::C2LinearBlock;
-};
-
-class GraphicViewBuddy : public C2GraphicView {
- using C2GraphicView::C2GraphicView;
- friend class ::C2ConstGraphicBlock;
- friend class ::C2GraphicBlock;
-};
-
-class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
- using C2Acquirable::C2Acquirable;
- friend class ::C2ConstGraphicBlock;
-};
-
-class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
- using C2Acquirable::C2Acquirable;
- friend class ::C2GraphicBlock;
-};
-
-class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
- using C2ConstGraphicBlock::C2ConstGraphicBlock;
- friend class ::C2GraphicBlock;
-};
-
-class GraphicBlockBuddy : public C2GraphicBlock {
- using C2GraphicBlock::C2GraphicBlock;
- friend class ::C2BasicGraphicBlockPool;
-};
-
-class BufferDataBuddy : public C2BufferData {
- using C2BufferData::C2BufferData;
- friend class ::C2Buffer;
-};
-
-} // namespace
-
-/* ========================================== 1D BLOCK ========================================= */
-
-struct C2_HIDE _C2BlockPoolData;
-
-/**
- * This class is the base class for all 1D block and view implementations.
- *
- * This is basically just a placeholder for the underlying 1D allocation and the range of the
- * alloted portion to this block. There is also a placeholder for a blockpool data.
- */
-class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
-public:
- _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
- size_t offset = 0, size_t size = ~(size_t)0)
- : _C2LinearRangeAspect(alloc.get(), offset, size),
- mAllocation(alloc),
- mPoolData(poolData) { }
-
- _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
- : _C2LinearRangeAspect(&other, offset, size),
- mAllocation(other.mAllocation),
- mPoolData(other.mPoolData) { }
-
- /** returns const pool data */
- std::shared_ptr<const _C2BlockPoolData> poolData() const {
- return mPoolData;
- }
-
- /** returns native handle */
- const C2Handle *handle() const {
- return mAllocation ? mAllocation->handle() : nullptr;
- }
-
- /** returns the allocator's ID */
- C2Allocator::id_t getAllocatorId() const {
- // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
- return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
- }
-
- std::shared_ptr<C2LinearAllocation> getAllocation() const {
- return mAllocation;
- }
-
-private:
- std::shared_ptr<C2LinearAllocation> mAllocation;
- std::shared_ptr<_C2BlockPoolData> mPoolData;
-};
-
-/**
- * This class contains the mapped data pointer, and the potential error.
- *
- * range is the mapped range of the underlying allocation (which is part of the allotted
- * range).
- */
-class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
-public:
- _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
- size_t offset = 0, size_t size = ~(size_t)0)
- : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
-
- _C2MappedBlock1DImpl(c2_status_t error)
- : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
- // CHECK(error != C2_OK);
- }
-
- const uint8_t *data() const {
- return mData;
- }
-
- uint8_t *data() {
- return mData;
- }
-
- c2_status_t error() const {
- return mError;
- }
-
-private:
- uint8_t *mData;
- c2_status_t mError;
-};
-
-/**
- * Block implementation.
- */
-class C2Block1D::Impl : public _C2Block1DImpl {
- using _C2Block1DImpl::_C2Block1DImpl;
-};
-
-const C2Handle *C2Block1D::handle() const {
- return mImpl->handle();
-};
-
-C2Allocator::id_t C2Block1D::getAllocatorId() const {
- return mImpl->getAllocatorId();
-};
-
-C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
- // always clamp subrange to parent (impl) range for safety
- : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
-}
-
-/**
- * Read view implementation.
- *
- * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
- * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
- * subrange of Impl range starting at mImpl->offset() + _mOffset.
- */
-class C2ReadView::Impl : public _C2MappedBlock1DImpl {
- using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
-};
-
-C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
- : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
- mImpl(impl),
- mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
-
-C2ReadView::C2ReadView(c2_status_t error)
- : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
- // CHECK(error != C2_OK);
-}
-
-const uint8_t *C2ReadView::data() const {
- return mImpl->error() ? nullptr : mImpl->data() + mOffset;
-}
-
-c2_status_t C2ReadView::error() const {
- return mImpl->error();
-}
-
-C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
- C2LinearRange subRange(*this, offset, size);
- return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
-}
-
-/**
- * Write view implementation.
- */
-class C2WriteView::Impl : public _C2MappedBlock1DImpl {
- using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
-};
-
-C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
-// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
-// this is what we have to do.
-// TODO: use childRange
- : _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
-
-C2WriteView::C2WriteView(c2_status_t error)
- : _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
-
-uint8_t *C2WriteView::base() { return mImpl->data(); }
-
-uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
-
-c2_status_t C2WriteView::error() const { return mImpl->error(); }
-
-/**
- * Const linear block implementation.
- */
-C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
- : C2Block1D(impl, range), mFence(fence) { }
-
-C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
- void *base = nullptr;
- uint32_t len = size();
- c2_status_t error = mImpl->getAllocation()->map(
- offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
- // TODO: wait on fence
- if (error == C2_OK) {
- std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
- new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
- [base, len](ReadViewBuddy::Impl *i) {
- (void)i->getAllocation()->unmap(base, len, nullptr);
- delete i;
- });
- return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
- } else {
- return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
- }
-}
-
-C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
- C2LinearRange subRange(*mImpl, offset_, size_);
- return C2ConstLinearBlock(mImpl, subRange, mFence);
-}
-
-/**
- * Linear block implementation.
- */
-C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
- : C2Block1D(impl, range) { }
-
-C2Acquirable<C2WriteView> C2LinearBlock::map() {
- void *base = nullptr;
- uint32_t len = size();
- c2_status_t error = mImpl->getAllocation()->map(
- offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
- // TODO: wait on fence
- if (error == C2_OK) {
- std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
- new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
- [base, len](WriteViewBuddy::Impl *i) {
- (void)i->getAllocation()->unmap(base, len, nullptr);
- delete i;
- });
- return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
- } else {
- return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
- }
-}
-
-C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
- return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
-}
-
-C2BasicLinearBlockPool::C2BasicLinearBlockPool(
- const std::shared_ptr<C2Allocator> &allocator)
- : mAllocator(allocator) { }
-
-c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
- uint32_t capacity,
- C2MemoryUsage usage,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- block->reset();
-
- std::shared_ptr<C2LinearAllocation> alloc;
- c2_status_t err = mAllocator->newLinearAllocation(capacity, usage, &alloc);
- if (err != C2_OK) {
- return err;
- }
-
- *block = _C2BlockFactory::CreateLinearBlock(alloc);
-
- return C2_OK;
-}
-
-std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
- const std::shared_ptr<C2LinearAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
- std::shared_ptr<C2Block1D::Impl> impl =
- std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
- return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
-}
-
-/**
- * Wrapped C2Allocator which is injected to buffer pool on behalf of
- * C2BlockPool.
- */
-class _C2BufferPoolAllocator : public BufferPoolAllocator {
-public:
- _C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
- : mAllocator(allocator) {}
-
- ~_C2BufferPoolAllocator() override {}
-
- ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc) override;
-
- bool compatible(const std::vector<uint8_t> &newParams,
- const std::vector<uint8_t> &oldParams) override;
-
- // Methods for codec2 component (C2BlockPool).
- /**
- * Transforms linear allocation parameters for C2Allocator to parameters
- * for buffer pool.
- *
- * @param capacity size of linear allocation
- * @param usage memory usage pattern for linear allocation
- * @param params allocation parameters for buffer pool
- */
- void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
- std::vector<uint8_t> *params);
-
- /**
- * Transforms graphic allocation parameters for C2Allocator to parameters
- * for buffer pool.
- *
- * @param width width of graphic allocation
- * @param height height of graphic allocation
- * @param format color format of graphic allocation
- * @param params allocation parameter for buffer pool
- */
- void getGraphicParams(uint32_t width, uint32_t height,
- uint32_t format, C2MemoryUsage usage,
- std::vector<uint8_t> *params);
-
- /**
- * Transforms an existing native handle to an C2LinearAllcation.
- * Wrapper to C2Allocator#priorLinearAllocation
- */
- c2_status_t priorLinearAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2LinearAllocation> *c2Allocation);
-
- /**
- * Transforms an existing native handle to an C2GraphicAllcation.
- * Wrapper to C2Allocator#priorGraphicAllocation
- */
- c2_status_t priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *c2Allocation);
-
-private:
- static constexpr int kMaxIntParams = 5; // large enough number;
-
- enum AllocType : uint8_t {
- ALLOC_NONE = 0,
-
- ALLOC_LINEAR,
- ALLOC_GRAPHIC,
- };
-
- union AllocParams {
- struct {
- AllocType allocType;
- C2MemoryUsage usage;
- uint32_t params[kMaxIntParams];
- } data;
- uint8_t array[0];
-
- AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
- AllocParams(C2MemoryUsage usage, uint32_t capacity)
- : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
- AllocParams(
- C2MemoryUsage usage,
- uint32_t width, uint32_t height, uint32_t format)
- : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
- };
-
- const std::shared_ptr<C2Allocator> mAllocator;
-};
-
-struct LinearAllocationDtor {
- LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
- : mAllocation(alloc) {}
-
- void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
-
- const std::shared_ptr<C2LinearAllocation> mAllocation;
-};
-
-ResultStatus _C2BufferPoolAllocator::allocate(
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc) {
- AllocParams c2Params;
- memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
- std::shared_ptr<C2LinearAllocation> c2Linear;
- c2_status_t status = C2_BAD_VALUE;
- switch(c2Params.data.allocType) {
- case ALLOC_NONE:
- break;
- case ALLOC_LINEAR:
- status = mAllocator->newLinearAllocation(
- c2Params.data.params[0], c2Params.data.usage, &c2Linear);
- if (status == C2_OK && c2Linear) {
- BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
- if (ptr) {
- *alloc = std::shared_ptr<BufferPoolAllocation>(
- ptr, LinearAllocationDtor(c2Linear));
- if (*alloc) {
- return ResultStatus::OK;
- }
- delete ptr;
- }
- return ResultStatus::NO_MEMORY;
- }
- break;
- case ALLOC_GRAPHIC:
- // TODO
- break;
- default:
- break;
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-bool _C2BufferPoolAllocator::compatible(
- const std::vector<uint8_t> &newParams,
- const std::vector<uint8_t> &oldParams) {
- size_t newSize = newParams.size();
- size_t oldSize = oldParams.size();
-
- // TODO: support not exact matching. e.g) newCapacity < oldCapacity
- if (newSize == oldSize) {
- for (size_t i = 0; i < newSize; ++i) {
- if (newParams[i] != oldParams[i]) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
-
-void _C2BufferPoolAllocator::getLinearParams(
- uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
- AllocParams c2Params(usage, capacity);
- params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
-}
-
-void _C2BufferPoolAllocator::getGraphicParams(
- uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
- std::vector<uint8_t> *params) {
- AllocParams c2Params(usage, width, height, format);
- params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
-}
-
-c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2LinearAllocation> *c2Allocation) {
- return mAllocator->priorLinearAllocation(handle, c2Allocation);
-}
-
-c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
- return mAllocator->priorGraphicAllocation(handle, c2Allocation);
-}
-
-class C2PooledBlockPool::Impl {
-public:
- Impl(const std::shared_ptr<C2Allocator> &allocator)
- : mInit(C2_OK),
- mBufferPoolManager(ClientManager::getInstance()),
- mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
- if (mAllocator && mBufferPoolManager) {
- if (mBufferPoolManager->create(
- mAllocator, &mConnectionId) == ResultStatus::OK) {
- return;
- }
- }
- mInit = C2_NO_INIT;
- }
-
- ~Impl() {
- if (mInit == C2_OK) {
- mBufferPoolManager->close(mConnectionId);
- }
- }
-
- c2_status_t fetchLinearBlock(
- uint32_t capacity, C2MemoryUsage usage,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- block->reset();
- if (mInit != C2_OK) {
- return mInit;
- }
- std::vector<uint8_t> params;
- mAllocator->getLinearParams(capacity, usage, ¶ms);
- std::shared_ptr<_C2BlockPoolData> poolData;
- ResultStatus status = mBufferPoolManager->allocate(
- mConnectionId, params, &poolData);
- if (status == ResultStatus::OK) {
- std::shared_ptr<C2LinearAllocation> alloc;
- c2_status_t err = mAllocator->priorLinearAllocation(
- poolData->mHandle, &alloc);
- if (err == C2_OK && poolData && alloc) {
- *block = _C2BlockFactory::CreateLinearBlock(
- alloc, poolData, 0, capacity);
- if (*block) {
- return C2_OK;
- }
- }
- return C2_NO_MEMORY;
- }
- if (status == ResultStatus::NO_MEMORY) {
- return C2_NO_MEMORY;
- }
- return C2_CORRUPTED;
- }
-
-private:
- c2_status_t mInit;
- const android::sp<ClientManager> mBufferPoolManager;
- ConnectionId mConnectionId; // locally
- const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
-};
-
-C2PooledBlockPool::C2PooledBlockPool(
- const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
- : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
-
-C2PooledBlockPool::~C2PooledBlockPool() {
-}
-
-c2_status_t C2PooledBlockPool::fetchLinearBlock(
- uint32_t capacity,
- C2MemoryUsage usage,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- if (mImpl) {
- return mImpl->fetchLinearBlock(capacity, usage, block);
- }
- return C2_CORRUPTED;
-}
-
-/* ========================================== 2D BLOCK ========================================= */
-
-/**
- * Implementation that is shared between all 2D blocks and views.
- *
- * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
- *
- * For views' Impl's crop is the mapped portion - which for now is always the
- * allotted crop.
- */
-class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
-public:
- /**
- * Impl's crop is always the or part of the allotted crop of the allocation.
- */
- _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
- const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
- : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
- mAllocation(alloc),
- mPoolData(poolData) { }
-
- /** returns const pool data */
- std::shared_ptr<const _C2BlockPoolData> poolData() const {
- return mPoolData;
- }
-
- /** returns native handle */
- const C2Handle *handle() const {
- return mAllocation ? mAllocation->handle() : nullptr;
- }
-
- /** returns the allocator's ID */
- C2Allocator::id_t getAllocatorId() const {
- // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
- return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
- }
-
- std::shared_ptr<C2GraphicAllocation> getAllocation() const {
- return mAllocation;
- }
-
-private:
- std::shared_ptr<C2GraphicAllocation> mAllocation;
- std::shared_ptr<_C2BlockPoolData> mPoolData;
-};
-
-class C2_HIDE _C2MappingBlock2DImpl
- : public _C2Block2DImpl, public std::enable_shared_from_this<_C2MappingBlock2DImpl> {
-public:
- using _C2Block2DImpl::_C2Block2DImpl;
-
- /**
- * This class contains the mapped data pointer, and the potential error.
- */
- struct Mapped {
- private:
- friend class _C2MappingBlock2DImpl;
-
- Mapped(const std::shared_ptr<_C2Block2DImpl> &impl, bool writable, C2Fence *fence __unused)
- : mImpl(impl), mWritable(writable) {
- memset(mData, 0, sizeof(mData));
- const C2Rect crop = mImpl->crop();
- // gralloc requires mapping the whole region of interest as we cannot
- // map multiple regions
- mError = mImpl->getAllocation()->map(
- crop,
- { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
- nullptr,
- &mLayout,
- mData);
- if (mError != C2_OK) {
- memset(&mLayout, 0, sizeof(mLayout));
- memset(mData, 0, sizeof(mData));
- memset(mOffsetData, 0, sizeof(mData));
- } else {
- // TODO: validate plane layout and
- // adjust data pointers to the crop region's top left corner.
- // fail if it is not on a subsampling boundary
- for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
- const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
- const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
- if (crop.left % colSampling || crop.right() % colSampling
- || crop.top % rowSampling || crop.bottom() % rowSampling) {
- // cannot calculate data pointer
- mImpl->getAllocation()->unmap(mData, crop, nullptr);
- memset(&mLayout, 0, sizeof(mLayout));
- memset(mData, 0, sizeof(mData));
- memset(mOffsetData, 0, sizeof(mData));
- mError = C2_BAD_VALUE;
- return;
- }
- mOffsetData[planeIx] =
- mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
- + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
- }
- }
- }
-
- explicit Mapped(c2_status_t error)
- : mImpl(nullptr), mWritable(false), mError(error) {
- // CHECK(error != C2_OK);
- memset(&mLayout, 0, sizeof(mLayout));
- memset(mData, 0, sizeof(mData));
- memset(mOffsetData, 0, sizeof(mData));
- }
-
- public:
- ~Mapped() {
- if (mData[0] != nullptr) {
- mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
- }
- }
-
- /** returns mapping status */
- c2_status_t error() const { return mError; }
-
- /** returns data pointer */
- uint8_t *const *data() const { return mOffsetData; }
-
- /** returns the plane layout */
- C2PlanarLayout layout() const { return mLayout; }
-
- /** returns whether the mapping is writable */
- bool writable() const { return mWritable; }
-
- private:
- const std::shared_ptr<_C2Block2DImpl> mImpl;
- bool mWritable;
- c2_status_t mError;
- uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
- uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
- C2PlanarLayout mLayout;
- };
-
- /**
- * Maps the allotted region.
- *
- * If already mapped and it is currently in use, returns the existing mapping.
- * If fence is provided, an acquire fence is stored there.
- */
- std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
- std::lock_guard<std::mutex> lock(mMappedLock);
- std::shared_ptr<Mapped> existing = mMapped.lock();
- if (!existing) {
- existing = std::shared_ptr<Mapped>(new Mapped(shared_from_this(), writable, fence));
- mMapped = existing;
- } else {
- // if we mapped the region read-only, we cannot remap it read-write
- if (writable && !existing->writable()) {
- existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
- }
- if (fence != nullptr) {
- *fence = C2Fence();
- }
- }
- return existing;
- }
-
-private:
- std::weak_ptr<Mapped> mMapped;
- std::mutex mMappedLock;
-};
-
-class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
-public:
- _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
- std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
- : _C2Block2DImpl(impl), mMapping(mapping) {
- }
-
- std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
-
-private:
- std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
-};
-
-/**
- * Block implementation.
- */
-class C2Block2D::Impl : public _C2MappingBlock2DImpl {
- using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
-};
-
-const C2Handle *C2Block2D::handle() const {
- return mImpl->handle();
-}
-
-C2Allocator::id_t C2Block2D::getAllocatorId() const {
- return mImpl->getAllocatorId();
-}
-
-C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
- // always clamp subsection to parent (impl) crop for safety
- : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
-}
-
-/**
- * Graphic view implementation.
- *
- * range of Impl is the mapped range of the underlying allocation. range of View is the current
- * crop.
- */
-class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
- using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
-};
-
-C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
- : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
-}
-
-const uint8_t *const *C2GraphicView::data() const {
- return mImpl->mapping()->data();
-}
-
-uint8_t *const *C2GraphicView::data() {
- return mImpl->mapping()->data();
-}
-
-const C2PlanarLayout C2GraphicView::layout() const {
- return mImpl->mapping()->layout();
-}
-
-const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
- return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
-}
-
-C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
- return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
-}
-
-c2_status_t C2GraphicView::error() const {
- return mImpl->mapping()->error();
-}
-
-/**
- * Const graphic block implementation.
- */
-C2ConstGraphicBlock::C2ConstGraphicBlock(
- std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence)
- : C2Block2D(impl, section), mFence(fence) { }
-
-C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
- C2Fence fence;
- std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
- mImpl->map(false /* writable */, &fence);
- std::shared_ptr<GraphicViewBuddy::Impl> gvi =
- std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
- return AcquirableConstGraphicViewBuddy(
- mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
-}
-
-C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
- return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
-}
-
-/**
- * Graphic block implementation.
- */
-C2GraphicBlock::C2GraphicBlock(
- std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
- : C2Block2D(impl, section) { }
-
-C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
- C2Fence fence;
- std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
- mImpl->map(true /* writable */, &fence);
- std::shared_ptr<GraphicViewBuddy::Impl> gvi =
- std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
- return AcquirableGraphicViewBuddy(
- mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
-}
-
-C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
- return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
-}
-
-/**
- * Basic block pool implementations.
- */
-C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
- const std::shared_ptr<C2Allocator> &allocator)
- : mAllocator(allocator) {}
-
-c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
- uint32_t width,
- uint32_t height,
- uint32_t format,
- C2MemoryUsage usage,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
- block->reset();
-
- std::shared_ptr<C2GraphicAllocation> alloc;
- c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
- if (err != C2_OK) {
- return err;
- }
-
- *block = _C2BlockFactory::CreateGraphicBlock(alloc);
-
- return C2_OK;
-}
-
-std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
- const std::shared_ptr<C2GraphicAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
- std::shared_ptr<C2Block2D::Impl> impl =
- std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
- return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
-}
-
-/* ========================================== BUFFER ========================================= */
-
-class C2BufferData::Impl {
-public:
- explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
- : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
- mLinearBlocks(blocks) {
- }
-
- explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
- : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
- mGraphicBlocks(blocks) {
- }
-
- Type type() const { return mType; }
- const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
- const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
-
-private:
- Type mType;
- std::vector<C2ConstLinearBlock> mLinearBlocks;
- std::vector<C2ConstGraphicBlock> mGraphicBlocks;
-};
-
-C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
-C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
-
-C2BufferData::Type C2BufferData::type() const { return mImpl->type(); }
-
-const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
- return mImpl->linearBlocks();
-}
-
-const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
- return mImpl->graphicBlocks();
-}
-
-class C2Buffer::Impl {
-public:
- Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
- : mThis(thiz), mData(blocks) {}
- Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
- : mThis(thiz), mData(blocks) {}
-
- ~Impl() {
- for (const auto &pair : mNotify) {
- pair.first(mThis, pair.second);
- }
- }
-
- const C2BufferData &data() const { return mData; }
-
- c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
- auto it = std::find_if(
- mNotify.begin(), mNotify.end(),
- [onDestroyNotify, arg] (const auto &pair) {
- return pair.first == onDestroyNotify && pair.second == arg;
- });
- if (it != mNotify.end()) {
- return C2_DUPLICATE;
- }
- mNotify.emplace_back(onDestroyNotify, arg);
- return C2_OK;
- }
-
- c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
- auto it = std::find_if(
- mNotify.begin(), mNotify.end(),
- [onDestroyNotify, arg] (const auto &pair) {
- return pair.first == onDestroyNotify && pair.second == arg;
- });
- if (it == mNotify.end()) {
- return C2_NOT_FOUND;
- }
- mNotify.erase(it);
- return C2_OK;
- }
-
- std::vector<std::shared_ptr<const C2Info>> info() const {
- std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
- std::transform(
- mInfos.begin(), mInfos.end(), result.begin(),
- [] (const auto &elem) { return elem.second; });
- return result;
- }
-
- c2_status_t setInfo(const std::shared_ptr<C2Info> &info) {
- // To "update" you need to erase the existing one if any, and then insert.
- (void) mInfos.erase(info->type());
- (void) mInfos.insert({ info->type(), info });
- return C2_OK;
- }
-
- bool hasInfo(C2Param::Type index) const {
- return mInfos.count(index.type()) > 0;
- }
-
- std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
- auto it = mInfos.find(index.type());
- if (it == mInfos.end()) {
- return nullptr;
- }
- std::shared_ptr<C2Info> ret = it->second;
- (void) mInfos.erase(it);
- return ret;
- }
-
-private:
- C2Buffer * const mThis;
- BufferDataBuddy mData;
- std::map<C2Param::Type, std::shared_ptr<C2Info>> mInfos;
- std::list<std::pair<OnDestroyNotify, void *>> mNotify;
-};
-
-C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
- : mImpl(new Impl(this, blocks)) {}
-
-C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
- : mImpl(new Impl(this, blocks)) {}
-
-const C2BufferData C2Buffer::data() const { return mImpl->data(); }
-
-c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
- return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
-}
-
-c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
- return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
-}
-
-const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
- return mImpl->info();
-}
-
-c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
- return mImpl->setInfo(info);
-}
-
-bool C2Buffer::hasInfo(C2Param::Type index) const {
- return mImpl->hasInfo(index);
-}
-
-std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
- return mImpl->removeInfo(index);
-}
-
-// static
-std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
- return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
-}
-
-// static
-std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
- return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
-}
-
diff --git a/media/libstagefright/codec2/vndk/C2Config.cpp b/media/libstagefright/codec2/vndk/C2Config.cpp
deleted file mode 100644
index 6acf524..0000000
--- a/media/libstagefright/codec2/vndk/C2Config.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2017 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 "C2Config"
-
-/**
- * Define and initialize global config field descriptors in this cpp file
- */
-#define __C2_GENERATE_GLOBAL_VARS__
-#include <C2Config.h>
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
deleted file mode 100644
index 6f752ae..0000000
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <C2AllocatorGralloc.h>
-#include <C2AllocatorIon.h>
-#include <C2BufferPriv.h>
-#include <C2Component.h>
-#include <C2PlatformSupport.h>
-
-#define LOG_TAG "C2Store"
-#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <dlfcn.h>
-
-#include <map>
-#include <memory>
-#include <mutex>
-
-namespace android {
-
-/**
- * The platform allocator store provides basic allocator-types for the framework based on ion and
- * gralloc. Allocators are not meant to be updatable.
- *
- * \todo Provide allocator based on ashmem
- * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
- * \todo Make this allocator store extendable
- */
-class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
-public:
- C2PlatformAllocatorStoreImpl(
- /* ionmapper */
- );
-
- virtual c2_status_t fetchAllocator(
- id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
-
- virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
- const override {
- return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
- }
-
- virtual C2String getName() const override {
- return "android.allocator-store";
- }
-
-private:
- /// returns a shared-singleton ion allocator
- std::shared_ptr<C2Allocator> fetchIonAllocator();
-
- /// returns a shared-singleton gralloc allocator
- std::shared_ptr<C2Allocator> fetchGrallocAllocator();
-};
-
-C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
-}
-
-c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
- id_t id, std::shared_ptr<C2Allocator> *const allocator) {
- allocator->reset();
- switch (id) {
- // TODO: should we implement a generic registry for all, and use that?
- case C2PlatformAllocatorStore::ION:
- case C2AllocatorStore::DEFAULT_LINEAR:
- *allocator = fetchIonAllocator();
- break;
-
- case C2PlatformAllocatorStore::GRALLOC:
- case C2AllocatorStore::DEFAULT_GRAPHIC:
- *allocator = fetchGrallocAllocator();
- break;
-
- default:
- return C2_NOT_FOUND;
- }
- if (*allocator == nullptr) {
- return C2_NO_MEMORY;
- }
- return C2_OK;
-}
-
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
- static std::mutex mutex;
- static std::weak_ptr<C2Allocator> ionAllocator;
- std::lock_guard<std::mutex> lock(mutex);
- std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
- if (allocator == nullptr) {
- allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
- ionAllocator = allocator;
- }
- return allocator;
-}
-
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
- static std::mutex mutex;
- static std::weak_ptr<C2Allocator> grallocAllocator;
- std::lock_guard<std::mutex> lock(mutex);
- std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
- if (allocator == nullptr) {
- allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
- grallocAllocator = allocator;
- }
- return allocator;
-}
-
-std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
- return std::make_shared<C2PlatformAllocatorStoreImpl>();
-}
-
-c2_status_t GetCodec2BlockPool(
- C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
- std::shared_ptr<C2BlockPool> *pool) {
- pool->reset();
- if (!component) {
- return C2_BAD_VALUE;
- }
- // TODO support pre-registered block pools
- std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
- std::shared_ptr<C2Allocator> allocator;
- c2_status_t res = C2_NOT_FOUND;
-
- switch (id) {
- case C2BlockPool::BASIC_LINEAR:
- res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
- if (res == C2_OK) {
- *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
- }
- break;
- case C2BlockPool::BASIC_GRAPHIC:
- res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
- if (res == C2_OK) {
- *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
- }
- break;
- default:
- break;
- }
- return res;
-}
-
-c2_status_t CreateCodec2BlockPool(
- C2PlatformAllocatorStore::id_t allocatorId,
- std::shared_ptr<const C2Component> component,
- std::shared_ptr<C2BlockPool> *pool) {
- pool->reset();
- if (!component) {
- return C2_BAD_VALUE;
- }
- // TODO: support caching block pool along with GetCodec2BlockPool.
- static std::atomic_int sBlockPoolId(C2BlockPool::PLATFORM_START);
- std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
- std::shared_ptr<C2Allocator> allocator;
- c2_status_t res = C2_NOT_FOUND;
-
- switch (allocatorId) {
- case C2PlatformAllocatorStore::ION:
- res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
- if (res == C2_OK) {
- *pool = std::make_shared<C2PooledBlockPool>(allocator, sBlockPoolId++);
- if (!*pool) {
- res = C2_NO_MEMORY;
- }
- }
- break;
- case C2PlatformAllocatorStore::GRALLOC:
- // TODO: support gralloc
- break;
- default:
- break;
- }
- return res;
-}
-
-class C2PlatformComponentStore : public C2ComponentStore {
-public:
- virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
- virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
- virtual C2String getName() const override;
- virtual c2_status_t querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery> &fields) const override;
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
- virtual c2_status_t query_sm(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
- virtual c2_status_t createInterface(
- C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
- virtual c2_status_t createComponent(
- C2String name, std::shared_ptr<C2Component> *const component) override;
- virtual c2_status_t copyBuffer(
- std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
- virtual c2_status_t config_sm(
- const std::vector<C2Param*> ¶ms,
- std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
- C2PlatformComponentStore();
-
- virtual ~C2PlatformComponentStore() override = default;
-
-private:
-
- /**
- * An object encapsulating a loaded component module.
- *
- * \todo provide a way to add traits to known components here to avoid loading the .so-s
- * for listComponents
- */
- struct ComponentModule : public C2ComponentFactory,
- public std::enable_shared_from_this<ComponentModule> {
- virtual c2_status_t createComponent(
- c2_node_id_t id, std::shared_ptr<C2Component> *component,
- ComponentDeleter deleter = std::default_delete<C2Component>()) override;
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
- InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
-
- /**
- * \returns the traits of the component in this module.
- */
- std::shared_ptr<const C2Component::Traits> getTraits();
-
- /**
- * Creates an uninitialized component module.
- *
- * \param name[in] component name.
- *
- * \note Only used by ComponentLoader.
- */
- ComponentModule()
- : mInit(C2_NO_INIT),
- mLibHandle(nullptr),
- createFactory(nullptr),
- destroyFactory(nullptr),
- mComponentFactory(nullptr) {
- }
-
- /**
- * Initializes a component module with a given library path. Must be called exactly once.
- *
- * \note Only used by ComponentLoader.
- *
- * \param libPath[in] library path (or name)
- *
- * \retval C2_OK the component module has been successfully loaded
- * \retval C2_NO_MEMORY not enough memory to loading the component module
- * \retval C2_NOT_FOUND could not locate the component module
- * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
- * \retval C2_REFUSED permission denied to load the component module (unexpected)
- * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
- */
- c2_status_t init(std::string libPath);
-
- virtual ~ComponentModule() override;
-
- protected:
- std::recursive_mutex mLock; ///< lock protecting mTraits
- std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
-
- c2_status_t mInit; ///< initialization result
-
- void *mLibHandle; ///< loaded library handle
- C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
- C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
- C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
- };
-
- /**
- * An object encapsulating a loadable component module.
- *
- * \todo make this also work for enumerations
- */
- struct ComponentLoader {
- /**
- * Load the component module.
- *
- * This method simply returns the component module if it is already currently loaded, or
- * attempts to load it if it is not.
- *
- * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
- * This will be nullptr on error.
- *
- * \retval C2_OK the component module has been successfully loaded
- * \retval C2_NO_MEMORY not enough memory to loading the component module
- * \retval C2_NOT_FOUND could not locate the component module
- * \retval C2_CORRUPTED the component module could not be loaded
- * \retval C2_REFUSED permission denied to load the component module
- */
- c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
- c2_status_t res = C2_OK;
- std::lock_guard<std::mutex> lock(mMutex);
- std::shared_ptr<ComponentModule> localModule = mModule.lock();
- if (localModule == nullptr) {
- localModule = std::make_shared<ComponentModule>();
- res = localModule->init(mLibPath);
- if (res == C2_OK) {
- mModule = localModule;
- }
- }
- *module = localModule;
- return res;
- }
-
- /**
- * Creates a component loader for a specific library path (or name).
- */
- ComponentLoader(std::string libPath)
- : mLibPath(libPath) {}
-
- private:
- std::mutex mMutex; ///< mutex guarding the module
- std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
- std::string mLibPath; ///< library path (or name)
- };
-
- /**
- * Retrieves the component loader for a component.
- *
- * \return a non-ref-holding pointer to the component loader.
- *
- * \retval C2_OK the component loader has been successfully retrieved
- * \retval C2_NO_MEMORY not enough memory to locate the component loader
- * \retval C2_NOT_FOUND could not locate the component to be loaded
- * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
- * corrupted (this can happen if the name does not refer to an already
- * identified component but some components could not be loaded due to
- * bad library)
- * \retval C2_REFUSED permission denied to find the component loader for the named component
- * (this can happen if the name does not refer to an already identified
- * component but some components could not be loaded due to lack of
- * permissions)
- */
- c2_status_t findComponent(C2String name, ComponentLoader **loader);
-
- std::map<C2String, ComponentLoader> mComponents; ///< list of components
-};
-
-c2_status_t C2PlatformComponentStore::ComponentModule::init(std::string libPath) {
- ALOGV("in %s", __func__);
- ALOGV("loading dll");
- mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
- if (mLibHandle == nullptr) {
- // could be access/symbol or simply not being there
- ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
- mInit = C2_CORRUPTED;
- } else {
- createFactory =
- (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
- destroyFactory =
- (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
-
- mComponentFactory = createFactory();
- if (mComponentFactory == nullptr) {
- ALOGD("could not create factory in %s", libPath.c_str());
- mInit = C2_NO_MEMORY;
- } else {
- mInit = C2_OK;
- }
- }
- return mInit;
-}
-
-C2PlatformComponentStore::ComponentModule::~ComponentModule() {
- ALOGV("in %s", __func__);
- if (destroyFactory && mComponentFactory) {
- destroyFactory(mComponentFactory);
- }
- if (mLibHandle) {
- ALOGV("unloading dll");
- dlclose(mLibHandle);
- }
-}
-
-c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
- std::function<void(::C2ComponentInterface*)> deleter) {
- interface->reset();
- if (mInit != C2_OK) {
- return mInit;
- }
- std::shared_ptr<ComponentModule> module = shared_from_this();
- c2_status_t res = mComponentFactory->createInterface(
- id, interface, [module, deleter](C2ComponentInterface *p) mutable {
- // capture module so that we ensure we still have it while deleting interface
- deleter(p); // delete interface first
- module.reset(); // remove module ref (not technically needed)
- });
- return res;
-}
-
-c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
- c2_node_id_t id, std::shared_ptr<C2Component> *component,
- std::function<void(::C2Component*)> deleter) {
- component->reset();
- if (mInit != C2_OK) {
- return mInit;
- }
- std::shared_ptr<ComponentModule> module = shared_from_this();
- c2_status_t res = mComponentFactory->createComponent(
- id, component, [module, deleter](C2Component *p) mutable {
- // capture module so that we ensure we still have it while deleting component
- deleter(p); // delete component first
- module.reset(); // remove module ref (not technically needed)
- });
- return res;
-}
-
-std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
- std::unique_lock<std::recursive_mutex> lock(mLock);
- if (!mTraits) {
- std::shared_ptr<C2ComponentInterface> intf;
- c2_status_t res = createInterface(0, &intf);
- if (res != C2_OK) {
- ALOGD("failed to create interface: %d", res);
- return nullptr;
- }
-
- std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
- if (traits) {
- traits->name = intf->getName();
- // TODO: get this from interface properly.
- bool encoder = (traits->name.find("encoder") != std::string::npos);
- uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
- : C2PortMimeConfig::input::PARAM_TYPE;
- std::vector<std::unique_ptr<C2Param>> params;
- res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
- if (res != C2_OK) {
- ALOGD("failed to query interface: %d", res);
- return nullptr;
- }
- if (params.size() != 1u) {
- ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
- return nullptr;
- }
- C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
- if (mediaTypeConfig == nullptr) {
- ALOGD("failed to query media type");
- return nullptr;
- }
- traits->mediaType = mediaTypeConfig->m.value;
- // TODO: get this properly.
- traits->rank = 0x200;
- }
-
- mTraits = traits;
- }
- return mTraits;
-}
-
-C2PlatformComponentStore::C2PlatformComponentStore() {
- // TODO: move this also into a .so so it can be updated
- mComponents.emplace("c2.google.avc.decoder", "libstagefright_soft_c2avcdec.so");
- mComponents.emplace("c2.google.avc.encoder", "libstagefright_soft_c2avcenc.so");
- mComponents.emplace("c2.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
- mComponents.emplace("c2.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
- mComponents.emplace("c2.google.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
- mComponents.emplace("c2.google.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
- mComponents.emplace("c2.google.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
- mComponents.emplace("c2.google.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
- mComponents.emplace("c2.google.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
- mComponents.emplace("c2.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
- mComponents.emplace("c2.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
- mComponents.emplace("c2.google.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
- mComponents.emplace("c2.google.h263.decoder", "libstagefright_soft_c2h263dec.so");
- mComponents.emplace("c2.google.h263.encoder", "libstagefright_soft_c2h263enc.so");
- mComponents.emplace("c2.google.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
- mComponents.emplace("c2.google.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
- mComponents.emplace("c2.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
- mComponents.emplace("c2.google.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
- mComponents.emplace("c2.google.opus.decoder", "libstagefright_soft_c2opusdec.so");
- mComponents.emplace("c2.google.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
- mComponents.emplace("c2.google.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
- mComponents.emplace("c2.google.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
- mComponents.emplace("c2.google.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
- mComponents.emplace("c2.google.raw.decoder", "libstagefright_soft_c2rawdec.so");
- mComponents.emplace("c2.google.flac.decoder", "libstagefright_soft_c2flacdec.so");
- mComponents.emplace("c2.google.flac.encoder", "libstagefright_soft_c2flacenc.so");
- mComponents.emplace("c2.google.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
-}
-
-c2_status_t C2PlatformComponentStore::copyBuffer(
- std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
- (void)src;
- (void)dst;
- return C2_OMITTED;
-}
-
-c2_status_t C2PlatformComponentStore::query_sm(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
- // there are no supported configs
- (void)heapParams;
- return stackParams.empty() && heapParamIndices.empty() ? C2_OK : C2_BAD_INDEX;
-}
-
-c2_status_t C2PlatformComponentStore::config_sm(
- const std::vector<C2Param*> ¶ms,
- std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
- // there are no supported configs
- (void)failures;
- return params.empty() ? C2_OK : C2_BAD_INDEX;
-}
-
-std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
- // This method SHALL return within 500ms.
- std::vector<std::shared_ptr<const C2Component::Traits>> list;
- for (auto &it : mComponents) {
- ComponentLoader &loader = it.second;
- std::shared_ptr<ComponentModule> module;
- c2_status_t res = loader.fetchModule(&module);
- if (res == C2_OK) {
- std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
- if (traits) {
- list.push_back(traits);
- }
- }
- }
- return list;
-}
-
-c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
- *loader = nullptr;
- auto pos = mComponents.find(name);
- // TODO: check aliases
- if (pos == mComponents.end()) {
- return C2_NOT_FOUND;
- }
- *loader = &pos->second;
- return C2_OK;
-}
-
-c2_status_t C2PlatformComponentStore::createComponent(
- C2String name, std::shared_ptr<C2Component> *const component) {
- // This method SHALL return within 100ms.
- component->reset();
- ComponentLoader *loader;
- c2_status_t res = findComponent(name, &loader);
- if (res == C2_OK) {
- std::shared_ptr<ComponentModule> module;
- res = loader->fetchModule(&module);
- if (res == C2_OK) {
- // TODO: get a unique node ID
- res = module->createComponent(0, component);
- }
- }
- return res;
-}
-
-c2_status_t C2PlatformComponentStore::createInterface(
- C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
- // This method SHALL return within 100ms.
- interface->reset();
- ComponentLoader *loader;
- c2_status_t res = findComponent(name, &loader);
- if (res == C2_OK) {
- std::shared_ptr<ComponentModule> module;
- res = loader->fetchModule(&module);
- if (res == C2_OK) {
- // TODO: get a unique node ID
- res = module->createInterface(0, interface);
- }
- }
- return res;
-}
-
-c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
- // there are no supported config params
- (void)params;
- return C2_OK;
-}
-
-c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery> &fields) const {
- // there are no supported config params
- return fields.empty() ? C2_OK : C2_BAD_INDEX;
-}
-
-C2String C2PlatformComponentStore::getName() const {
- return "android.componentStore.platform";
-}
-
-std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
- // TODO
- return nullptr;
-}
-
-std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
- static std::mutex mutex;
- static std::weak_ptr<C2ComponentStore> platformStore;
- std::lock_guard<std::mutex> lock(mutex);
- std::shared_ptr<C2ComponentStore> store = platformStore.lock();
- if (store == nullptr) {
- store = std::make_shared<C2PlatformComponentStore>();
- platformStore = store;
- }
- return store;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp b/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
deleted file mode 100644
index 1b1b9be..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include "Accessor.h"
-#include "AccessorImpl.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
-Return<void> Accessor::connect(connect_cb _hidl_cb) {
- sp<Connection> connection;
- ConnectionId connectionId;
- const QueueDescriptor* fmqDesc;
-
- ResultStatus status = connect(&connection, &connectionId, &fmqDesc);
- if (status == ResultStatus::OK) {
- _hidl_cb(status, connection, connectionId, *fmqDesc);
- } else {
- _hidl_cb(status, nullptr, -1LL,
- android::hardware::MQDescriptorSync<BufferStatusMessage>(
- std::vector<android::hardware::GrantorDescriptor>(),
- nullptr /* nhandle */, 0 /* size */));
- }
- return Void();
-}
-
-Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
- : mImpl(new Impl(allocator)) {}
-
-Accessor::~Accessor() {
-}
-
-bool Accessor::isValid() {
- return (bool)mImpl;
-}
-
-ResultStatus Accessor::allocate(
- ConnectionId connectionId,
- const std::vector<uint8_t> ¶ms,
- BufferId *bufferId, const native_handle_t** handle) {
- if (mImpl) {
- return mImpl->allocate(connectionId, params, bufferId, handle);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::fetch(
- ConnectionId connectionId, TransactionId transactionId,
- BufferId bufferId, const native_handle_t** handle) {
- if (mImpl) {
- return mImpl->fetch(connectionId, transactionId, bufferId, handle);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::connect(
- sp<Connection> *connection, ConnectionId *pConnectionId,
- const QueueDescriptor** fmqDescPtr) {
- if (mImpl) {
- return mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::close(ConnectionId connectionId) {
- if (mImpl) {
- return mImpl->close(connectionId);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-//IAccessor* HIDL_FETCH_IAccessor(const char* /* name */) {
-// return new Accessor();
-//}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.h b/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
deleted file mode 100644
index ad42245..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
-
-#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <BufferPoolTypes.h>
-#include "BufferStatus.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct Connection;
-
-/**
- * A buffer pool accessor which enables a buffer pool to communicate with buffer
- * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
- */
-struct Accessor : public IAccessor {
- // Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
- Return<void> connect(connect_cb _hidl_cb) override;
-
- /**
- * Creates a buffer pool accessor which uses the specified allocator.
- *
- * @param allocator buffer allocator.
- */
- explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
-
- /** Destructs a buffer pool accessor. */
- ~Accessor();
-
- /** Returns whether the accessor is valid. */
- bool isValid();
-
- /** Allocates a buffer form a buffer pool.
- *
- * @param connectionId the connection id of the client.
- * @param params the allocation parameters.
- * @param bufferId the id of the allocated buffer.
- * @param handle the native handle of the allocated buffer.
- *
- * @return OK when a buffer is successfully allocated.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus allocate(
- ConnectionId connectionId,
- const std::vector<uint8_t>& params,
- BufferId *bufferId,
- const native_handle_t** handle);
-
- /**
- * Fetches a buffer for the specified transaction.
- *
- * @param connectionId the id of receiving connection(client).
- * @param transactionId the id of the transfer transaction.
- * @param bufferId the id of the buffer to be fetched.
- * @param handle the native handle of the fetched buffer.
- *
- * @return OK when a buffer is successfully fetched.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus fetch(
- ConnectionId connectionId,
- TransactionId transactionId,
- BufferId bufferId,
- const native_handle_t** handle);
-
- /**
- * Makes a connection to the buffer pool. The buffer pool client uses the
- * created connection in order to communicate with the buffer pool. An
- * FMQ for buffer status message is also created for the client.
- *
- * @param connection created connection
- * @param pConnectionId the id of the created connection
- * @param fmqDescPtr FMQ descriptor for shared buffer status message
- * queue between a buffer pool and the client.
- *
- * @return OK when a connection is successfully made.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus connect(
- sp<Connection> *connection, ConnectionId *pConnectionId,
- const QueueDescriptor** fmqDescPtr);
-
- /**
- * Closes the specified connection to the client.
- *
- * @param connectionId the id of the connection.
- *
- * @return OK when the connection is closed.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus close(ConnectionId connectionId);
-
-private:
- class Impl;
- std::unique_ptr<Impl> mImpl;
-};
-
-// FIXME: most likely delete, this is only for passthrough implementations
-// extern "C" IAccessor* HIDL_FETCH_IAccessor(const char* name);
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
deleted file mode 100644
index 32d76c0..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Copyright (C) 2018 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_TAG "bufferpool"
-//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <utils/Log.h>
-#include "AccessorImpl.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-// Buffer structure in bufferpool process
-struct InternalBuffer {
- BufferId mId;
- size_t mOwnerCount;
- size_t mTransactionCount;
- const std::shared_ptr<BufferPoolAllocation> mAllocation;
- const std::vector<uint8_t> mConfig;
-
- InternalBuffer(
- BufferId id,
- const std::shared_ptr<BufferPoolAllocation> &alloc,
- const std::vector<uint8_t> &allocConfig)
- : mId(id), mOwnerCount(0), mTransactionCount(0),
- mAllocation(alloc), mConfig(allocConfig) {}
-
- const native_handle_t *handle() {
- return mAllocation->handle();
- }
-};
-
-struct TransactionStatus {
- TransactionId mId;
- BufferId mBufferId;
- ConnectionId mSender;
- ConnectionId mReceiver;
- BufferStatus mStatus;
- int64_t mTimestampUs;
- bool mSenderValidated;
-
- TransactionStatus(const BufferStatusMessage &message, int64_t timestampUs) {
- mId = message.transactionId;
- mBufferId = message.bufferId;
- mStatus = message.newStatus;
- mTimestampUs = timestampUs;
- if (mStatus == BufferStatus::TRANSFER_TO) {
- mSender = message.connectionId;
- mReceiver = message.targetConnectionId;
- mSenderValidated = true;
- } else {
- mSender = -1LL;
- mReceiver = message.connectionId;
- mSenderValidated = false;
- }
- }
-};
-
-// Helper template methods for handling map of set.
-template<class T, class U>
-bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
- auto iter = mapOfSet->find(key);
- if (iter == mapOfSet->end()) {
- std::set<U> valueSet{value};
- mapOfSet->insert(std::make_pair(key, valueSet));
- return true;
- } else if (iter->second.find(value) == iter->second.end()) {
- iter->second.insert(value);
- return true;
- }
- return false;
-}
-
-template<class T, class U>
-bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
- bool ret = false;
- auto iter = mapOfSet->find(key);
- if (iter != mapOfSet->end()) {
- if (iter->second.erase(value) > 0) {
- ret = true;
- }
- if (iter->second.size() == 0) {
- mapOfSet->erase(iter);
- }
- }
- return ret;
-}
-
-template<class T, class U>
-bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
- auto iter = mapOfSet->find(key);
- if (iter != mapOfSet->end()) {
- auto setIter = iter->second.find(value);
- return setIter != iter->second.end();
- }
- return false;
-}
-
-
-int32_t Accessor::Impl::sPid = getpid();
-uint32_t Accessor::Impl::sSeqId = time(NULL);
-
-Accessor::Impl::Impl(
- const std::shared_ptr<BufferPoolAllocator> &allocator)
- : mAllocator(allocator) {}
-
-Accessor::Impl::~Impl() {
-}
-
-ResultStatus Accessor::Impl::connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr) {
- sp<Connection> newConnection = new Connection();
- ResultStatus status = ResultStatus::CRITICAL_ERROR;
- if (newConnection) {
- std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
- ConnectionId id = (int64_t)sPid << 32 | sSeqId;
- status = mBufferPool.mObserver.open(id, fmqDescPtr);
- if (status == ResultStatus::OK) {
- newConnection->initialize(accessor, id);
- *connection = newConnection;
- *pConnectionId = id;
- ++sSeqId;
- }
- }
- return status;
-}
-
-ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
- std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
- mBufferPool.processStatusMessages();
- mBufferPool.handleClose(connectionId);
- mBufferPool.mObserver.close(connectionId);
- return ResultStatus::OK;
-}
-
-ResultStatus Accessor::Impl::allocate(
- ConnectionId connectionId, const std::vector<uint8_t>& params,
- BufferId *bufferId, const native_handle_t** handle) {
- std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
- mBufferPool.processStatusMessages();
- ResultStatus status = ResultStatus::OK;
- if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
- status = mBufferPool.getNewBuffer(mAllocator, params, bufferId, handle);
- ALOGV("create a buffer %d : %u %p",
- status == ResultStatus::OK, *bufferId, *handle);
- }
- if (status == ResultStatus::OK) {
- // TODO: handle ownBuffer failure
- mBufferPool.handleOwnBuffer(connectionId, *bufferId);
- }
- return status;
-}
-
-ResultStatus Accessor::Impl::fetch(
- ConnectionId connectionId, TransactionId transactionId,
- BufferId bufferId, const native_handle_t** handle) {
- std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
- mBufferPool.processStatusMessages();
- auto found = mBufferPool.mTransactions.find(transactionId);
- if (found != mBufferPool.mTransactions.end() &&
- contains(&mBufferPool.mPendingTransactions,
- connectionId, transactionId)) {
- if (found->second->mSenderValidated &&
- found->second->mStatus == BufferStatus::TRANSFER_FROM &&
- found->second->mBufferId == bufferId) {
- found->second->mStatus = BufferStatus::TRANSFER_FETCH;
- auto bufferIt = mBufferPool.mBuffers.find(bufferId);
- if (bufferIt != mBufferPool.mBuffers.end()) {
- *handle = bufferIt->second->handle();
- return ResultStatus::OK;
- }
- }
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-void Accessor::Impl::sync() {
- // TODO: periodic jobs
- // transaction timeout, buffer cacheing TTL handling
- std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
- mBufferPool.processStatusMessages();
-}
-
-Accessor::Impl::Impl::BufferPool::BufferPool()
- : mTimestampUs(getTimestampNow()), mSeq(0) {}
-
-bool Accessor::Impl::BufferPool::handleOwnBuffer(
- ConnectionId connectionId, BufferId bufferId) {
-
- bool added = insert(&mUsingBuffers, connectionId, bufferId);
- if (added) {
- auto iter = mBuffers.find(bufferId);
- iter->second->mOwnerCount++;
- }
- insert(&mUsingConnections, bufferId, connectionId);
- return added;
-}
-
-bool Accessor::Impl::BufferPool::handleReleaseBuffer(
- ConnectionId connectionId, BufferId bufferId) {
- bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
- if (deleted) {
- auto iter = mBuffers.find(bufferId);
- iter->second->mOwnerCount--;
- if (iter->second->mOwnerCount == 0 &&
- iter->second->mTransactionCount == 0) {
- mFreeBuffers.insert(bufferId);
- }
- }
- erase(&mUsingConnections, bufferId, connectionId);
- ALOGV("release buffer %u : %d", bufferId, deleted);
- return deleted;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferTo(const BufferStatusMessage &message) {
- auto completed = mCompletedTransactions.find(
- message.transactionId);
- if (completed != mCompletedTransactions.end()) {
- // already completed
- mCompletedTransactions.erase(completed);
- return true;
- }
- // the buffer should exist and be owned.
- auto bufferIter = mBuffers.find(message.bufferId);
- if (bufferIter == mBuffers.end() ||
- !contains(&mUsingBuffers, message.connectionId, message.bufferId)) {
- return false;
- }
- auto found = mTransactions.find(message.transactionId);
- if (found != mTransactions.end()) {
- // transfer_from was received earlier.
- found->second->mSender = message.connectionId;
- found->second->mSenderValidated = true;
- return true;
- }
- // TODO: verify there is target connection Id
- mTransactions.insert(std::make_pair(
- message.transactionId,
- std::make_unique<TransactionStatus>(message, mTimestampUs)));
- insert(&mPendingTransactions, message.targetConnectionId,
- message.transactionId);
- bufferIter->second->mTransactionCount++;
- return true;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
- auto found = mTransactions.find(message.transactionId);
- if (found == mTransactions.end()) {
- // TODO: is it feasible to check ownership here?
- mTransactions.insert(std::make_pair(
- message.transactionId,
- std::make_unique<TransactionStatus>(message, mTimestampUs)));
- insert(&mPendingTransactions, message.connectionId,
- message.transactionId);
- auto bufferIter = mBuffers.find(message.bufferId);
- bufferIter->second->mTransactionCount++;
- } else {
- if (message.connectionId == found->second->mReceiver) {
- found->second->mStatus = BufferStatus::TRANSFER_FROM;
- }
- }
- return true;
-}
-
-bool Accessor::Impl::BufferPool::handleTransferResult(const BufferStatusMessage &message) {
- auto found = mTransactions.find(message.transactionId);
- if (found != mTransactions.end()) {
- bool deleted = erase(&mPendingTransactions, message.connectionId,
- message.transactionId);
- if (deleted) {
- if (!found->second->mSenderValidated) {
- mCompletedTransactions.insert(message.transactionId);
- }
- auto bufferIter = mBuffers.find(message.bufferId);
- if (message.newStatus == BufferStatus::TRANSFER_OK) {
- handleOwnBuffer(message.connectionId, message.bufferId);
- }
- bufferIter->second->mTransactionCount--;
- if (bufferIter->second->mOwnerCount == 0
- && bufferIter->second->mTransactionCount == 0) {
- mFreeBuffers.insert(message.bufferId);
- }
- }
- ALOGV("transfer finished %" PRIu64 " %u - %d", message.transactionId,
- message.bufferId, deleted);
- return deleted;
- }
- ALOGV("transfer not found %" PRIu64 " %u", message.transactionId,
- message.bufferId);
- return false;
-}
-
-void Accessor::Impl::BufferPool::processStatusMessages() {
- std::vector<BufferStatusMessage> messages;
- mObserver.getBufferStatusChanges(messages);
- mTimestampUs = getTimestampNow();
- for (BufferStatusMessage& message: messages) {
- bool ret = false;
- switch (message.newStatus) {
- case BufferStatus::NOT_USED:
- ret = handleReleaseBuffer(
- message.connectionId, message.bufferId);
- break;
- case BufferStatus::USED:
- // not happening
- break;
- case BufferStatus::TRANSFER_TO:
- ret = handleTransferTo(message);
- break;
- case BufferStatus::TRANSFER_FROM:
- ret = handleTransferFrom(message);
- break;
- case BufferStatus::TRANSFER_TIMEOUT:
- // TODO
- break;
- case BufferStatus::TRANSFER_LOST:
- // TODO
- break;
- case BufferStatus::TRANSFER_FETCH:
- // not happening
- break;
- case BufferStatus::TRANSFER_OK:
- case BufferStatus::TRANSFER_ERROR:
- ret = handleTransferResult(message);
- break;
- }
- if (ret == false) {
- ALOGW("buffer status message processing failure - message : %d "
- "connection : %" PRId64,
- message.newStatus, message.connectionId);
- }
- }
- messages.clear();
-}
-
-bool Accessor::Impl::BufferPool::handleClose(ConnectionId connectionId) {
- // Cleaning buffers
- auto buffers = mUsingBuffers.find(connectionId);
- if (buffers != mUsingBuffers.end()) {
- for (const BufferId& bufferId : buffers->second) {
- bool deleted = erase(&mUsingConnections, bufferId, connectionId);
- if (deleted) {
- auto bufferIter = mBuffers.find(bufferId);
- bufferIter->second->mOwnerCount--;
- if (bufferIter->second->mOwnerCount == 0 &&
- bufferIter->second->mTransactionCount == 0) {
- // TODO: handle freebuffer insert fail
- mFreeBuffers.insert(bufferId);
- }
- }
- }
- mUsingBuffers.erase(buffers);
- }
-
- // Cleaning transactions
- auto pending = mPendingTransactions.find(connectionId);
- if (pending != mPendingTransactions.end()) {
- for (const TransactionId& transactionId : pending->second) {
- auto iter = mTransactions.find(transactionId);
- if (iter != mTransactions.end()) {
- if (!iter->second->mSenderValidated) {
- mCompletedTransactions.insert(transactionId);
- }
- BufferId bufferId = iter->second->mBufferId;
- auto bufferIter = mBuffers.find(bufferId);
- bufferIter->second->mTransactionCount--;
- if (bufferIter->second->mOwnerCount == 0 &&
- bufferIter->second->mTransactionCount == 0) {
- // TODO: handle freebuffer insert fail
- mFreeBuffers.insert(bufferId);
- }
- mTransactions.erase(iter);
- }
- }
- }
- return true;
-}
-
-bool Accessor::Impl::BufferPool::getFreeBuffer(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- const std::vector<uint8_t> ¶ms, BufferId *pId,
- const native_handle_t** handle) {
- auto bufferIt = mFreeBuffers.begin();
- for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
- BufferId bufferId = *bufferIt;
- if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
- break;
- }
- }
- if (bufferIt != mFreeBuffers.end()) {
- BufferId id = *bufferIt;
- mFreeBuffers.erase(bufferIt);
- *handle = mBuffers[id]->handle();
- *pId = id;
- ALOGV("recycle a buffer %u %p", id, *handle);
- return true;
- }
- return false;
-}
-
-ResultStatus Accessor::Impl::BufferPool::getNewBuffer(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- const std::vector<uint8_t> ¶ms, BufferId *pId,
- const native_handle_t** handle) {
- std::shared_ptr<BufferPoolAllocation> alloc;
- ResultStatus status = allocator->allocate(params, &alloc);
-
- if (status == ResultStatus::OK) {
- BufferId bufferId = mSeq++;
- std::unique_ptr<InternalBuffer> buffer =
- std::make_unique<InternalBuffer>(
- bufferId, alloc, params);
- if (buffer) {
- auto res = mBuffers.insert(std::make_pair(
- bufferId, std::move(buffer)));
- if (res.second) {
- *handle = alloc->handle();
- *pId = bufferId;
- return ResultStatus::OK;
- }
- }
- return ResultStatus::NO_MEMORY;
- }
- return status;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
deleted file mode 100644
index 1260550..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
-
-#include <map>
-#include <set>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-struct InternalBuffer;
-struct TransactionStatus;
-
-/**
- * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
-class Accessor::Impl {
-public:
- Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
-
- ~Impl();
-
- ResultStatus connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr);
-
- ResultStatus close(ConnectionId connectionId);
-
- ResultStatus allocate(ConnectionId connectionId,
- const std::vector<uint8_t>& params,
- BufferId *bufferId,
- const native_handle_t** handle);
-
- ResultStatus fetch(ConnectionId connectionId,
- TransactionId transactionId,
- BufferId bufferId,
- const native_handle_t** handle);
-
- /** Processes pending buffer status messages */
- void sync();
-
-private:
- // ConnectionId = pid : (timestamp_created + seqId)
- // in order to guarantee uniqueness for each connection
- static uint32_t sSeqId;
- static int32_t sPid;
-
- const std::shared_ptr<BufferPoolAllocator> mAllocator;
-
- /**
- * Buffer pool implementation.
- *
- * Handles buffer status messages. Handles buffer allocation/recycling.
- * Handles buffer transfer between buffer pool clients.
- */
- struct BufferPool {
- private:
- std::mutex mMutex;
- int64_t mTimestampUs;
- BufferId mSeq;
- BufferStatusObserver mObserver;
-
- std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
- std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
-
- std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
- // Transactions completed before TRANSFER_TO message arrival.
- // Fetch does not occur for the transactions.
- // Only transaction id is kept for the transactions in short duration.
- std::set<TransactionId> mCompletedTransactions;
- // Currently active(pending) transations' status & information.
- std::map<TransactionId, std::unique_ptr<TransactionStatus>>
- mTransactions;
-
- std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
- std::set<BufferId> mFreeBuffers;
-
- public:
- /** Creates a buffer pool. */
- BufferPool();
-
- /**
- * Processes all pending buffer status messages, and returns the result.
- * Each status message is handled by methods with 'handle' prefix.
- */
- void processStatusMessages();
-
- /**
- * Handles a buffer being owned by a connection.
- *
- * @param connectionId the id of the buffer owning connection.
- * @param bufferId the id of the buffer.
- *
- * @return {@code true} when the buffer is owned,
- * {@code false} otherwise.
- */
- bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
-
- /**
- * Handles a buffer being released by a connection.
- *
- * @param connectionId the id of the buffer owning connection.
- * @param bufferId the id of the buffer.
- *
- * @return {@code true} when the buffer ownership is released,
- * {@code false} otherwise.
- */
- bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
-
- /**
- * Handles a transfer transaction start message from the sender.
- *
- * @param message a buffer status message for the transaction.
- *
- * @result {@code true} when transfer_to message is acknowledged,
- * {@code false} otherwise.
- */
- bool handleTransferTo(const BufferStatusMessage &message);
-
- /**
- * Handles a transfer transaction being acked by the receiver.
- *
- * @param message a buffer status message for the transaction.
- *
- * @result {@code true} when transfer_from message is acknowledged,
- * {@code false} otherwise.
- */
- bool handleTransferFrom(const BufferStatusMessage &message);
-
- /**
- * Handles a transfer transaction result message from the receiver.
- *
- * @param message a buffer status message for the transaction.
- *
- * @result {@code true} when the exisitng transaction is finished,
- * {@code false} otherwise.
- */
- bool handleTransferResult(const BufferStatusMessage &message);
-
- /**
- * Handles a connection being closed, and returns the result. All the
- * buffers and transactions owned by the connection will be cleaned up.
- * The related FMQ will be cleaned up too.
- *
- * @param connectionId the id of the connection.
- *
- * @result {@code true} when the connection existed,
- * {@code false} otherwise.
- */
- bool handleClose(ConnectionId connectionId);
-
- /**
- * Recycles a existing free buffer if it is possible.
- *
- * @param allocator the buffer allocator
- * @param params the allocation parameters.
- * @param pId the id of the recycled buffer.
- * @param handle the native handle of the recycled buffer.
- *
- * @return {@code true} when a buffer is recycled, {@code false}
- * otherwise.
- */
- bool getFreeBuffer(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- const std::vector<uint8_t> ¶ms,
- BufferId *pId, const native_handle_t **handle);
-
- /**
- * Creates a new buffer.
- *
- * @param allocator the buffer allocator
- * @param params the allocator parameters
- * @param pId the buffer id for the newly allocated buffer.
- * @param handle the native handle for the newly allocated buffer.
- *
- * @return OK when an allocation is successfully allocated.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus getNewBuffer(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- const std::vector<uint8_t> ¶ms, BufferId *pId,
- const native_handle_t **handle);
-
- friend class Accessor::Impl;
- } mBufferPool;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace ufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
deleted file mode 100644
index 1ea1f35..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-cc_library {
- name: "libstagefright_bufferpool@1.0",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- srcs: [
- "Accessor.cpp",
- "AccessorImpl.cpp",
- "BufferPoolClient.cpp",
- "BufferStatus.cpp",
- "ClientManager.cpp",
- "Connection.cpp",
- ],
- export_include_dirs: [
- "include",
- ],
- include_dirs: [
- "frameworks/av/media/libstagefright/codec2/vndk/bufferpool/include",
- ],
- shared_libs: [
- "libcutils",
- "libfmq",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libutils",
- "android.hardware.media.bufferpool@1.0",
- ],
-}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp
deleted file mode 100644
index 7cb4ba9..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Copyright (C) 2018 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_TAG "bufferpool"
-//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-#include <thread>
-#include <utils/Log.h>
-#include "BufferPoolClient.h"
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-static constexpr int64_t kReceiveTimeoutUs = 5000; // 5ms
-static constexpr int kPostMaxRetry = 3;
-static constexpr int kCacheTtlUs = 500000; // TODO: tune
-
-class BufferPoolClient::Impl
- : public std::enable_shared_from_this<BufferPoolClient::Impl> {
-public:
- explicit Impl(const sp<Accessor> &accessor);
-
- explicit Impl(const sp<IAccessor> &accessor);
-
- bool isValid() {
- return mValid;
- }
-
- ConnectionId getConnectionId() {
- return mConnectionId;
- }
-
- sp<IAccessor> &getAccessor() {
- return mAccessor;
- }
-
- ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- ResultStatus receive(
- TransactionId transactionId, BufferId bufferId,
- int64_t timestampUs, std::shared_ptr<_C2BlockPoolData> *buffer);
-
- void postBufferRelease(BufferId bufferId);
-
- bool postSend(
- BufferId bufferId, ConnectionId receiver,
- TransactionId *transactionId, int64_t *timestampUs);
-private:
-
- bool postReceive(
- BufferId bufferId, TransactionId transactionId,
- int64_t timestampUs);
-
- bool postReceiveResult(
- BufferId bufferId, TransactionId transactionId, bool result);
-
- bool syncReleased();
-
- ResultStatus allocateBufferHandle(
- const std::vector<uint8_t>& params, BufferId *bufferId,
- native_handle_t **handle);
-
- ResultStatus fetchBufferHandle(
- TransactionId transactionId, BufferId bufferId,
- native_handle_t **handle);
-
-
- struct BlockPoolDataDtor;
- struct ClientBuffer;
-
- bool mLocal;
- bool mValid;
- sp<IAccessor> mAccessor;
- sp<Connection> mLocalConnection;
- sp<IConnection> mRemoteConnection;
- uint32_t mSeqId;
- ConnectionId mConnectionId;
-
- // CachedBuffers
- struct {
- std::mutex mLock;
- bool creating;
- std::condition_variable mCreateCv;
- std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
- } mCache;
-
- // FMQ - release notifier
- struct {
- std::mutex mLock;
- // TODO: use only one list?(using one list may dealy sending messages?)
- std::list<BufferId> mReleasingIds;
- std::list<BufferId> mReleasedIds;
- std::unique_ptr<BufferStatusChannel> mStatusChannel;
- } mReleasing;
-};
-
-struct BufferPoolClient::Impl::BlockPoolDataDtor {
- BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
- : mImpl(impl) {}
-
- void operator()(_C2BlockPoolData *buffer) {
- BufferId id = buffer->mId;
- delete buffer;
-
- auto impl = mImpl.lock();
- if (impl && impl->isValid()) {
- impl->postBufferRelease(id);
- }
- }
- const std::weak_ptr<BufferPoolClient::Impl> mImpl;
-};
-
-struct BufferPoolClient::Impl::ClientBuffer {
-private:
- bool mInvalidated; // TODO: implement
- int64_t mExpireUs;
- bool mHasCache;
- _C2BlockPoolData mBuffer;
- std::weak_ptr<_C2BlockPoolData> mCache;
-
- void updateExpire() {
- mExpireUs = getTimestampNow() + kCacheTtlUs;
- }
-
-public:
- ClientBuffer(BufferId id, native_handle_t *handle)
- : mInvalidated(false), mHasCache(false), mBuffer(id, handle) {
- (void)mInvalidated;
- mExpireUs = getTimestampNow() + kCacheTtlUs;
- }
-
- bool expire() const {
- int64_t now = getTimestampNow();
- return now >= mExpireUs;
- }
-
- bool hasCache() const {
- return mHasCache;
- }
-
- std::shared_ptr<_C2BlockPoolData> fetchCache() {
- if (mHasCache) {
- std::shared_ptr<_C2BlockPoolData> cache = mCache.lock();
- if (cache) {
- updateExpire();
- }
- return cache;
- }
- return nullptr;
- }
-
- std::shared_ptr<_C2BlockPoolData> createCache(
- const std::shared_ptr<BufferPoolClient::Impl> &impl) {
- if (!mHasCache) {
- // Allocates a raw ptr in order to avoid sending #postBufferRelease
- // from deleter, in case of native_handle_clone failure.
- _C2BlockPoolData *ptr = new _C2BlockPoolData(
- mBuffer.mId, native_handle_clone(mBuffer.mHandle));
- if (ptr && ptr->mHandle != NULL) {
- std::shared_ptr<_C2BlockPoolData>
- cache(ptr, BlockPoolDataDtor(impl));
- if (cache) {
- mCache = cache;
- mHasCache = true;
- updateExpire();
- return cache;
- }
- }
- if (ptr) {
- delete ptr;
- }
- }
- return nullptr;
- }
-
- bool onCacheRelease() {
- if (mHasCache) {
- // TODO: verify mCache is not valid;
- mHasCache = false;
- return true;
- }
- return false;
- }
-};
-
-BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
- : mLocal(true), mAccessor(accessor), mSeqId(0) {
- mValid = false;
- const QueueDescriptor *fmqDesc;
- ResultStatus status = accessor->connect(
- &mLocalConnection, &mConnectionId, &fmqDesc);
- if (status == ResultStatus::OK) {
- mReleasing.mStatusChannel =
- std::make_unique<BufferStatusChannel>(*fmqDesc);
- mValid = mReleasing.mStatusChannel &&
- mReleasing.mStatusChannel->isValid();
- }
-}
-
-BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
- : mLocal(false), mAccessor(accessor), mSeqId(0) {
- mValid = false;
- bool& valid = mValid;
- sp<IConnection>& outConnection = mRemoteConnection;
- ConnectionId& id = mConnectionId;
- std::unique_ptr<BufferStatusChannel>& outChannel =
- mReleasing.mStatusChannel;
- accessor->connect(
- [&valid, &outConnection, &id, &outChannel]
- (ResultStatus status, sp<IConnection> connection,
- ConnectionId connectionId, const QueueDescriptor& desc) {
- if (status == ResultStatus::OK) {
- outConnection = connection;
- id = connectionId;
- outChannel = std::make_unique<BufferStatusChannel>(desc);
- if (outChannel && outChannel->isValid()) {
- valid = true;
- }
- }
- });
-}
-
-ResultStatus BufferPoolClient::Impl::allocate(
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (!mLocal || !mLocalConnection || !mValid) {
- return ResultStatus::CRITICAL_ERROR;
- }
- BufferId bufferId;
- native_handle_t *handle = NULL;
- buffer->reset();
- ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
- if (status == ResultStatus::OK) {
- if (handle) {
- std::unique_lock<std::mutex> lock(mCache.mLock);
- syncReleased();
- auto cacheIt = mCache.mBuffers.find(bufferId);
- if (cacheIt != mCache.mBuffers.end()) {
- // TODO: verify it is recycled. (not having active ref)
- mCache.mBuffers.erase(cacheIt);
- }
- auto clientBuffer = std::make_unique<ClientBuffer>(
- bufferId, handle);
- if (clientBuffer) {
- auto result = mCache.mBuffers.insert(std::make_pair(
- bufferId, std::move(clientBuffer)));
- if (result.second) {
- *buffer = result.first->second->createCache(
- shared_from_this());
- }
- }
- }
- if (!*buffer) {
- ALOGV("client cache creation failure %d: %" PRId64,
- handle != NULL, mConnectionId);
- status = ResultStatus::NO_MEMORY;
- postBufferRelease(bufferId);
- }
- }
- return status;
-}
-
-ResultStatus BufferPoolClient::Impl::receive(
- TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (!mValid) {
- return ResultStatus::CRITICAL_ERROR;
- }
- if (timestampUs != 0) {
- timestampUs += kReceiveTimeoutUs;
- }
- if (!postReceive(bufferId, transactionId, timestampUs)) {
- return ResultStatus::CRITICAL_ERROR;
- }
- ResultStatus status = ResultStatus::CRITICAL_ERROR;
- buffer->reset();
- while(1) {
- std::unique_lock<std::mutex> lock(mCache.mLock);
- syncReleased();
- auto cacheIt = mCache.mBuffers.find(bufferId);
- if (cacheIt != mCache.mBuffers.end()) {
- if (cacheIt->second->hasCache()) {
- *buffer = cacheIt->second->fetchCache();
- if (!*buffer) {
- // check transfer time_out
- lock.unlock();
- std::this_thread::yield();
- continue;
- }
- ALOGV("client receive from reference %" PRId64, mConnectionId);
- break;
- } else {
- *buffer = cacheIt->second->createCache(shared_from_this());
- ALOGV("client receive from cache %" PRId64, mConnectionId);
- break;
- }
- } else {
- if (!mCache.creating) {
- mCache.creating = true;
- lock.unlock();
- native_handle_t* handle = NULL;
- status = fetchBufferHandle(transactionId, bufferId, &handle);
- lock.lock();
- if (status == ResultStatus::OK) {
- if (handle) {
- auto clientBuffer = std::make_unique<ClientBuffer>(
- bufferId, handle);
- if (clientBuffer) {
- auto result = mCache.mBuffers.insert(
- std::make_pair(bufferId, std::move(
- clientBuffer)));
- if (result.second) {
- *buffer = result.first->second->createCache(
- shared_from_this());
- }
- }
- }
- if (!*buffer) {
- status = ResultStatus::NO_MEMORY;
- }
- }
- mCache.creating = false;
- lock.unlock();
- mCache.mCreateCv.notify_all();
- break;
- }
- mCache.mCreateCv.wait(lock);
- }
- }
- bool posted = postReceiveResult(bufferId, transactionId,
- *buffer ? true : false);
- ALOGV("client receive %" PRId64 " - %u : %s (%d)", mConnectionId, bufferId,
- *buffer ? "ok" : "fail", posted);
- if (*buffer) {
- if (!posted) {
- buffer->reset();
- return ResultStatus::CRITICAL_ERROR;
- }
- return ResultStatus::OK;
- }
- return status;
-}
-
-
-void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- mReleasing.mReleasingIds.push_back(bufferId);
- mReleasing.mStatusChannel->postBufferRelease(
- mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
-}
-
-// TODO: revise ad-hoc posting data structure
-bool BufferPoolClient::Impl::postSend(
- BufferId bufferId, ConnectionId receiver,
- TransactionId *transactionId, int64_t *timestampUs) {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- *timestampUs = getTimestampNow();
- *transactionId = (mConnectionId << 32) | mSeqId++;
- // TODO: retry, add timeout, target?
- return mReleasing.mStatusChannel->postBufferStatusMessage(
- *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
- receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
-}
-
-bool BufferPoolClient::Impl::postReceive(
- BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
- for (int i = 0; i < kPostMaxRetry; ++i) {
- std::unique_lock<std::mutex> lock(mReleasing.mLock);
- int64_t now = getTimestampNow();
- if (timestampUs == 0 || now < timestampUs) {
- bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
- transactionId, bufferId, BufferStatus::TRANSFER_FROM,
- mConnectionId, -1, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
- if (result) {
- return true;
- }
- lock.unlock();
- std::this_thread::yield();
- } else {
- mReleasing.mStatusChannel->postBufferStatusMessage(
- transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
- mConnectionId, -1, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
- return false;
- }
- }
- return false;
-}
-
-bool BufferPoolClient::Impl::postReceiveResult(
- BufferId bufferId, TransactionId transactionId, bool result) {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- // TODO: retry, add timeout
- return mReleasing.mStatusChannel->postBufferStatusMessage(
- transactionId, bufferId,
- result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
- mConnectionId, -1, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
-}
-
-// should have mCache.mLock
-bool BufferPoolClient::Impl::syncReleased() {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- if (mReleasing.mReleasingIds.size() > 0) {
- mReleasing.mStatusChannel->postBufferRelease(
- mConnectionId, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
- }
- if (mReleasing.mReleasedIds.size() > 0) {
- for (BufferId& id: mReleasing.mReleasedIds) {
- ALOGV("client release buffer %" PRId64 " - %u", mConnectionId, id);
- auto found = mCache.mBuffers.find(id);
- if (found != mCache.mBuffers.end()) {
- if (!found->second->onCacheRelease()) {
- // should not happen!
- ALOGW("client %" PRId64 "cache release status inconsitent!",
- mConnectionId);
- }
- if (found->second->expire()) {
- ALOGV("client evict buffer from cache %" PRId64 " - %u",
- mConnectionId, id);
- mCache.mBuffers.erase(found);
- }
- } else {
- // should not happen!
- ALOGW("client %" PRId64 "cache status inconsitent!",
- mConnectionId);
- }
- }
- mReleasing.mReleasedIds.clear();
- return true;
- }
- return false;
-}
-
-ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
- const std::vector<uint8_t>& params, BufferId *bufferId,
- native_handle_t** handle) {
- if (mLocalConnection) {
- const native_handle_t* allocHandle = NULL;
- ResultStatus status = mLocalConnection->allocate(
- params, bufferId, &allocHandle);
- if (status == ResultStatus::OK) {
- *handle = native_handle_clone(allocHandle);
- }
- ALOGV("client allocate result %" PRId64 "%d : %u clone %p",
- mConnectionId, status == ResultStatus::OK,
- *handle ? *bufferId : 0 , *handle);
- return status;
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
- TransactionId transactionId, BufferId bufferId,
- native_handle_t **handle) {
- sp<IConnection> connection;
- if (mLocal) {
- connection = mLocalConnection;
- } else {
- connection = mRemoteConnection;
- }
- ResultStatus status;
- connection->fetch(
- transactionId, bufferId,
- [&status, &handle]
- (ResultStatus outStatus, Buffer outBuffer) {
- status = outStatus;
- if (status == ResultStatus::OK) {
- *handle = native_handle_clone(
- outBuffer.buffer.getNativeHandle());
- }
- });
- return status;
-}
-
-
-BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
-}
-
-BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
-}
-
-BufferPoolClient::~BufferPoolClient() {
- // TODO: how to handle orphaned buffers?
-}
-
-bool BufferPoolClient::isValid() {
- return mImpl && mImpl->isValid();
-}
-
-ConnectionId BufferPoolClient::getConnectionId() {
- if (isValid()) {
- return mImpl->getConnectionId();
- }
- return -1;
-}
-
-ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
- if (isValid()) {
- *accessor = mImpl->getAccessor();
- return ResultStatus::OK;
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::allocate(
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (isValid()) {
- return mImpl->allocate(params, buffer);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::receive(
- TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (isValid()) {
- return mImpl->receive(transactionId, bufferId, timestampUs, buffer);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus BufferPoolClient::postSend(
- ConnectionId receiverId,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId,
- int64_t *timestampUs) {
- if (isValid()) {
- bool result = mImpl->postSend(
- buffer->mId, receiverId, transactionId, timestampUs);
- return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h
deleted file mode 100644
index a6111b5..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
-
-#include <memory>
-#include <cutils/native_handle.h>
-#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
-#include <android/hardware/media/bufferpool/1.0/IConnection.h>
-#include <BufferPoolTypes.h>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::bufferpool::V1_0::IAccessor;
-using ::android::hardware::media::bufferpool::V1_0::IConnection;
-using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
-using ::android::sp;
-
-/**
- * A buffer pool client for a buffer pool. For a specific buffer pool, at most
- * one buffer pool client exists per process. This class will not be exposed
- * outside. A buffer pool client will be used via ClientManager.
- */
-class BufferPoolClient {
-public:
- /**
- * Creates a buffer pool client from a local buffer pool
- * (via ClientManager#create).
- */
- explicit BufferPoolClient(const sp<Accessor> &accessor);
-
- /**
- * Creates a buffer pool client from a remote buffer pool
- * (via ClientManager#registerSender).
- * Note: A buffer pool client created with remote buffer pool cannot
- * allocate a buffer.
- */
- explicit BufferPoolClient(const sp<IAccessor> &accessor);
-
- /** Destructs a buffer pool client. */
- ~BufferPoolClient();
-
-private:
- bool isValid();
-
- ConnectionId getConnectionId();
-
- ResultStatus getAccessor(sp<IAccessor> *accessor);
-
- ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- ResultStatus receive(TransactionId transactionId,
- BufferId bufferId,
- int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- ResultStatus postSend(ConnectionId receiver,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId,
- int64_t *timestampUs);
-
- class Impl;
- std::shared_ptr<Impl> mImpl;
-
- friend struct ClientManager;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp
deleted file mode 100644
index 4fc88c6..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2018 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_TAG "bufferpool"
-//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-#include <time.h>
-#include "BufferStatus.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-int64_t getTimestampNow() {
- int64_t stamp;
- struct timespec ts;
- // TODO: CLOCK_MONOTONIC_COARSE?
- clock_gettime(CLOCK_MONOTONIC, &ts);
- stamp = ts.tv_nsec / 1000;
- stamp += (ts.tv_sec * 1000000LL);
- return stamp;
-}
-
-static constexpr int kNumElementsInQueue = 1024*16;
-
-ResultStatus BufferStatusObserver::open(
- ConnectionId id, const QueueDescriptor** fmqDescPtr) {
- if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
- // TODO: id collision log?
- return ResultStatus::CRITICAL_ERROR;
- }
- std::unique_ptr<BufferStatusQueue> queue =
- std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
- if (!queue || queue->isValid() == false) {
- *fmqDescPtr = NULL;
- return ResultStatus::NO_MEMORY;
- } else {
- *fmqDescPtr = queue->getDesc();
- }
- auto result = mBufferStatusQueues.insert(
- std::make_pair(id, std::move(queue)));
- if (!result.second) {
- *fmqDescPtr = NULL;
- return ResultStatus::NO_MEMORY;
- }
- return ResultStatus::OK;
-}
-
-ResultStatus BufferStatusObserver::close(ConnectionId id) {
- if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
- return ResultStatus::CRITICAL_ERROR;
- }
- mBufferStatusQueues.erase(id);
- return ResultStatus::OK;
-}
-
-void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
- for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
- BufferStatusMessage message;
- size_t avail = it->second->availableToRead();
- while (avail > 0) {
- if (!it->second->read(&message, 1)) {
- // Since avaliable # of reads are already confiremd,
- // this should not happen.
- // TODO: error handling (supurious client?)
- ALOGW("FMQ message cannot be read from %" PRId64, it->first);
- return;
- }
- message.connectionId = it->first;
- messages.push_back(message);
- --avail;
- }
- }
-}
-
-BufferStatusChannel::BufferStatusChannel(
- const QueueDescriptor &fmqDesc) {
- std::unique_ptr<BufferStatusQueue> queue =
- std::make_unique<BufferStatusQueue>(fmqDesc);
- if (!queue || queue->isValid() == false) {
- mValid = false;
- return;
- }
- mValid = true;
- mBufferStatusQueue = std::move(queue);
-}
-
-bool BufferStatusChannel::isValid() {
- return mValid;
-}
-
-void BufferStatusChannel::postBufferRelease(
- ConnectionId connectionId,
- std::list<BufferId> &pending, std::list<BufferId> &posted) {
- if (mValid && pending.size() > 0) {
- size_t avail = mBufferStatusQueue->availableToWrite();
- avail = std::min(avail, pending.size());
- BufferStatusMessage message;
- for (size_t i = 0 ; i < avail; ++i) {
- BufferId id = pending.front();
- message.newStatus = BufferStatus::NOT_USED;
- message.bufferId = id;
- message.connectionId = connectionId;
- if (!mBufferStatusQueue->write(&message, 1)) {
- // Since avaliable # of writes are already confiremd,
- // this should not happen.
- // TODO: error handing?
- ALOGW("FMQ message cannot be sent from %" PRId64, connectionId);
- return;
- }
- pending.pop_front();
- posted.push_back(id);
- }
- }
-}
-
-bool BufferStatusChannel::postBufferStatusMessage(
- TransactionId transactionId, BufferId bufferId,
- BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
- std::list<BufferId> &pending, std::list<BufferId> &posted) {
- if (mValid) {
- size_t avail = mBufferStatusQueue->availableToWrite();
- size_t numPending = pending.size();
- if (avail >= numPending + 1) {
- BufferStatusMessage release, message;
- for (size_t i = 0; i < numPending; ++i) {
- BufferId id = pending.front();
- release.newStatus = BufferStatus::NOT_USED;
- release.bufferId = id;
- release.connectionId = connectionId;
- if (!mBufferStatusQueue->write(&release, 1)) {
- // Since avaliable # of writes are already confiremd,
- // this should not happen.
- // TODO: error handling?
- ALOGW("FMQ message cannot be sent from %" PRId64,
- connectionId);
- return false;
- }
- pending.pop_front();
- posted.push_back(id);
- }
- message.transactionId = transactionId;
- message.bufferId = bufferId;
- message.newStatus = status;
- message.connectionId = connectionId;
- message.targetConnectionId = targetId;
- // TODO : timesatamp
- message.timestampUs = 0;
- if (!mBufferStatusQueue->write(&message, 1)) {
- // Since avaliable # of writes are already confiremd,
- // this should not happen.
- ALOGW("FMQ message cannot be sent from %" PRId64, connectionId);
- return false;
- }
- return true;
- }
- }
- return false;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h
deleted file mode 100644
index 82303cb..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
-
-#include <android/hardware/media/bufferpool/1.0/types.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <memory>
-#include <mutex>
-#include <vector>
-#include <list>
-#include <BufferPoolTypes.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-/** Returns monotonic timestamp in Us since fixed point in time. */
-int64_t getTimestampNow();
-
-/**
- * A collection of FMQ for a buffer pool. buffer ownership/status change
- * messages are sent via the FMQs from the clients.
- */
-class BufferStatusObserver {
-private:
- std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
- mBufferStatusQueues;
-
-public:
- /** Creates an FMQ for the specified connection(client).
- *
- * @param connectionId connection Id of the specified client.
- * @param fmqDescPtr double ptr of created FMQ's descriptor.
- *
- * @return OK if FMQ is created successfully.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus open(ConnectionId id, const QueueDescriptor** fmqDescPtr);
-
- /** Closes an FMQ for the specified connection(client).
- *
- * @param connectionId connection Id of the specified client.
- *
- * @return OK if the specified connection is closed successfully.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus close(ConnectionId id);
-
- /** Retrieves all pending FMQ buffer status messages from clients.
- *
- * @param messages retrieved pending messages.
- */
- void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
-};
-
-/**
- * An FMQ for a buffer pool client. buffer ownership/status change messages
- * are sent via the fmq to the buffer pool.
- */
-class BufferStatusChannel {
-private:
- bool mValid;
- std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
-
-public:
- /**
- * Connects to an FMQ from a descriptor of the created FMQ.
- *
- * @param fmqDesc Descriptor of the created FMQ.
- */
- BufferStatusChannel(const QueueDescriptor &fmqDesc);
-
- /** Returns whether the FMQ is connected successfully. */
- bool isValid();
-
- /**
- * Posts a buffer release message to the buffer pool.
- *
- * @param connectionId connection Id of the client.
- * @param pending currently pending buffer release messages.
- * @param posted posted buffer release messages.
- */
- void postBufferRelease(
- ConnectionId connectionId,
- std::list<BufferId> &pending, std::list<BufferId> &posted);
-
- /**
- * Posts a buffer status message regarding the specified buffer
- * transfer transaction.
- *
- * @param transactionId Id of the specified transaction.
- * @param bufferId buffer Id of the specified transaction.
- * @param status new status of the buffer.
- * @param connectionId connection Id of the client.
- * @param targetId connection Id of the receiver(only when the sender
- * posts a status message).
- * @param pending currently pending buffer release messages.
- * @param posted posted buffer release messages.
- *
- * @return {@code true} when the specified message is posted,
- * {@code false} otherwise.
- */
- bool postBufferStatusMessage(
- TransactionId transactionId,
- BufferId bufferId,
- BufferStatus status,
- ConnectionId connectionId,
- ConnectionId targetId,
- std::list<BufferId> &pending, std::list<BufferId> &posted);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp b/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
deleted file mode 100644
index 89aee8b..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <ClientManager.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include "BufferPoolClient.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-static constexpr int64_t kRegisterTimeoutUs = 500000; // 0.5 sec
-
-class ClientManager::Impl {
-public:
- Impl();
-
- ResultStatus registerSender(const sp<IAccessor> &accessor,
- ConnectionId *pConnectionId);
-
- ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
- ConnectionId *pConnectionId);
-
- ResultStatus close(ConnectionId connectionId);
-
- ResultStatus allocate(ConnectionId connectionId,
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- ResultStatus receive(ConnectionId connectionId,
- TransactionId transactionId,
- BufferId bufferId,
- int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- ResultStatus postSend(ConnectionId connectionId,
- ConnectionId receiverId,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId,
- int64_t *timestampUs);
-
- ResultStatus getAccessor(ConnectionId connectionId,
- sp<IAccessor> *accessor);
-
-private:
- // In order to prevent deadlock between multiple locks,
- // Always lock ClientCache.lock before locking ActiveClients.lock.
- struct ClientCache {
- // This lock is held for brief duration.
- // Blocking operation is not performed holding the lock.
- std::mutex mMutex;
- std::map<const wp<IAccessor>, const std::weak_ptr<BufferPoolClient>>
- mClients;
- std::condition_variable mConnectCv;
- bool mConnecting;
-
- ClientCache() : mConnecting(false) {}
- } mCache;
-
- // Active clients which can be retrieved via ConnectionId
- struct ActiveClients {
- // This lock is held for brief duration.
- // Blocking operation is not performed holding the lock.
- std::mutex mMutex;
- std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
- mClients;
- } mActive;
-
-};
-
-ClientManager::Impl::Impl() {}
-
-ResultStatus ClientManager::Impl::registerSender(
- const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
- int64_t timeoutUs = getTimestampNow() + kRegisterTimeoutUs;
- do {
- std::unique_lock<std::mutex> lock(mCache.mMutex);
- auto it = mCache.mClients.find(accessor);
- if (it != mCache.mClients.end()) {
- const std::shared_ptr<BufferPoolClient> client = it->second.lock();
- if (client) {
- *pConnectionId = client->getConnectionId();
- return ResultStatus::ALREADY_EXISTS;
- }
- mCache.mClients.erase(it);
- }
- if (!mCache.mConnecting) {
- mCache.mConnecting = true;
- lock.unlock();
- ResultStatus result = ResultStatus::OK;
- const std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
- lock.lock();
- if (!client) {
- result = ResultStatus::NO_MEMORY;
- } else if (!client->isValid()) {
- result = ResultStatus::CRITICAL_ERROR;
- }
- if (result == ResultStatus::OK) {
- // TODO: handle insert fail. (malloc fail)
- const std::weak_ptr<BufferPoolClient> wclient = client;
- mCache.mClients.insert(std::make_pair(accessor, wclient));
- ConnectionId conId = client->getConnectionId();
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- mActive.mClients.insert(std::make_pair(conId, client));
- }
- *pConnectionId = conId;
- }
- mCache.mConnecting = false;
- lock.unlock();
- mCache.mConnectCv.notify_all();
- return result;
- }
- mCache.mConnectCv.wait_for(
- lock, std::chrono::microseconds(kRegisterTimeoutUs));
- } while (getTimestampNow() < timeoutUs);
- // TODO: return timeout error
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::Impl::create(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- ConnectionId *pConnectionId) {
- const sp<Accessor> accessor = new Accessor(allocator);
- if (!accessor || !accessor->isValid()) {
- return ResultStatus::CRITICAL_ERROR;
- }
- std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
- if (!client || !client->isValid()) {
- return ResultStatus::CRITICAL_ERROR;
- }
- {
- // TODO: handle insert fail. (malloc fail)
- std::lock_guard<std::mutex> lock(mCache.mMutex);
- const wp<Accessor> waccessor = accessor;
- const std::weak_ptr<BufferPoolClient> wclient = client;
- mCache.mClients.insert(std::make_pair(waccessor, wclient));
- ConnectionId conId = client->getConnectionId();
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- mActive.mClients.insert(std::make_pair(conId, client));
- }
- *pConnectionId = conId;
- }
- return ResultStatus::OK;
-}
-
-ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
- std::lock_guard<std::mutex> lock1(mCache.mMutex);
- std::lock_guard<std::mutex> lock2(mActive.mMutex);
- auto it = mActive.mClients.find(connectionId);
- if (it != mActive.mClients.end()) {
- sp<IAccessor> accessor;
- if (it->second->getAccessor(&accessor) == ResultStatus::OK) {
- mCache.mClients.erase(accessor);
- }
- mActive.mClients.erase(connectionId);
- return ResultStatus::OK;
- }
- return ResultStatus::NOT_FOUND;
-}
-
-ResultStatus ClientManager::Impl::allocate(
- ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- std::shared_ptr<BufferPoolClient> client;
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- auto it = mActive.mClients.find(connectionId);
- if (it == mActive.mClients.end()) {
- return ResultStatus::NOT_FOUND;
- }
- client = it->second;
- }
- return client->allocate(params, buffer);
-}
-
-ResultStatus ClientManager::Impl::receive(
- ConnectionId connectionId, TransactionId transactionId,
- BufferId bufferId, int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- std::shared_ptr<BufferPoolClient> client;
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- auto it = mActive.mClients.find(connectionId);
- if (it == mActive.mClients.end()) {
- return ResultStatus::NOT_FOUND;
- }
- client = it->second;
- }
- return client->receive(transactionId, bufferId, timestampUs, buffer);
-}
-
-ResultStatus ClientManager::Impl::postSend(
- ConnectionId connectionId, ConnectionId receiverId,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId, int64_t *timestampUs) {
- std::shared_ptr<BufferPoolClient> client;
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- auto it = mActive.mClients.find(connectionId);
- if (it == mActive.mClients.end()) {
- return ResultStatus::NOT_FOUND;
- }
- client = it->second;
- }
- return client->postSend(receiverId, buffer, transactionId, timestampUs);
-}
-
-ResultStatus ClientManager::Impl::getAccessor(
- ConnectionId connectionId, sp<IAccessor> *accessor) {
- std::shared_ptr<BufferPoolClient> client;
- {
- std::lock_guard<std::mutex> lock(mActive.mMutex);
- auto it = mActive.mClients.find(connectionId);
- if (it == mActive.mClients.end()) {
- return ResultStatus::NOT_FOUND;
- }
- client = it->second;
- }
- return client->getAccessor(accessor);
-}
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
-Return<void> ClientManager::registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) {
- if (mImpl) {
- ConnectionId connectionId = -1;
- ResultStatus status = mImpl->registerSender(bufferPool, &connectionId);
- _hidl_cb(status, connectionId);
- } else {
- _hidl_cb(ResultStatus::CRITICAL_ERROR, -1);
- }
- return Void();
-}
-
-// Methods for local use.
-sp<ClientManager> ClientManager::sInstance;
-std::mutex ClientManager::sInstanceLock;
-
-sp<ClientManager> ClientManager::getInstance() {
- std::lock_guard<std::mutex> lock(sInstanceLock);
- if (!sInstance) {
- sInstance = new ClientManager();
- }
- return sInstance;
-}
-
-ClientManager::ClientManager() : mImpl(new Impl()) {}
-
-ClientManager::~ClientManager() {
-}
-
-ResultStatus ClientManager::create(
- const std::shared_ptr<BufferPoolAllocator> &allocator,
- ConnectionId *pConnectionId) {
- if (mImpl) {
- return mImpl->create(allocator, pConnectionId);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::close(ConnectionId connectionId) {
- if (mImpl) {
- return mImpl->close(connectionId);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::allocate(
- ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (mImpl) {
- return mImpl->allocate(connectionId, params, buffer);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::receive(
- ConnectionId connectionId, TransactionId transactionId,
- BufferId bufferId, int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer) {
- if (mImpl) {
- return mImpl->receive(connectionId, transactionId, bufferId,
- timestampUs, buffer);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::postSend(
- ConnectionId connectionId, ConnectionId receiverId,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId, int64_t* timestampUs) {
- if (mImpl) {
- return mImpl->postSend(connectionId, receiverId, buffer,
- transactionId, timestampUs);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus ClientManager::getAccessor(
- ConnectionId connectionId, sp<IAccessor> *accessor) {
- if (mImpl) {
- return mImpl->getAccessor(connectionId, accessor);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-//IClientManager* HIDL_FETCH_IClientManager(const char* /* name */) {
-// return new ClientManager();
-//}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp b/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp
deleted file mode 100644
index 7b385b8..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include "Connection.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
-Return<void> Connection::fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) {
- ResultStatus status = ResultStatus::CRITICAL_ERROR;
- if (mInitialized && mAccessor) {
- const native_handle_t *handle = NULL;
- status = mAccessor->fetch(
- mConnectionId, transactionId, bufferId, &handle);
- if (status == ResultStatus::OK) {
- _hidl_cb(status, Buffer{bufferId, handle});
- return Void();
- }
- }
- _hidl_cb(status, Buffer{0, nullptr});
- return Void();
-}
-
-Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
-
-Connection::~Connection() {
- if (mInitialized && mAccessor) {
- mAccessor->close(mConnectionId);
- }
-}
-
-void Connection::initialize(
- const sp<Accessor>& accessor, ConnectionId connectionId) {
- if (!mInitialized) {
- mAccessor = accessor;
- mConnectionId = connectionId;
- mInitialized = true;
- }
-}
-
-ResultStatus Connection::allocate(
- const std::vector<uint8_t> ¶ms, BufferId *bufferId,
- const native_handle_t **handle) {
- if (mInitialized && mAccessor) {
- return mAccessor->allocate(mConnectionId, params, bufferId, handle);
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-
-// Methods from ::android::hidl::base::V1_0::IBase follow.
-
-//IConnection* HIDL_FETCH_IConnection(const char* /* name */) {
-// return new Connection();
-//}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Connection.h b/media/libstagefright/codec2/vndk/bufferpool/Connection.h
deleted file mode 100644
index 47ddbcb..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/Connection.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
-
-#include <android/hardware/media/bufferpool/1.0/IConnection.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <BufferPoolTypes.h>
-#include "Accessor.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::media::bufferpool::V1_0::implementation::Accessor;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct Connection : public IConnection {
- // Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
- Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
-
- /**
- * Allocates a buffer using the specified parameters. Recycles a buffer if
- * it is possible. The returned buffer can be transferred to other remote
- * clients(Connection).
- *
- * @param params allocation parameters.
- * @param bufferId Id of the allocated buffer.
- * @param handle native handle of the allocated buffer.
- *
- * @return OK if a buffer is successfully allocated.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- BufferId *bufferId, const native_handle_t **handle);
-
- /** Destructs a connection. */
- ~Connection();
-
- /** Creates a connection. */
- Connection();
-
- /**
- * Initializes with the specified buffer pool and the connection id.
- * The connection id should be unique in the whole system.
- *
- * @param accessor the specified buffer pool.
- * @param connectionId Id.
- */
- void initialize(const sp<Accessor> &accessor, ConnectionId connectionId);
-
-private:
- bool mInitialized;
- sp<Accessor> mAccessor;
- ConnectionId mConnectionId;
-};
-
-// FIXME: most likely delete, this is only for passthrough implementations
-// extern "C" IConnection* HIDL_FETCH_IConnection(const char* name);
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h b/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
deleted file mode 100644
index 0cf023c..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
-
-#include <android/hardware/media/bufferpool/1.0/types.h>
-#include <cutils/native_handle.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-struct __attribute__((visibility("hidden"))) _C2BlockPoolData {
- uint32_t mId; //BufferId
- native_handle_t *mHandle;
-
- _C2BlockPoolData() : mId(0), mHandle(NULL) {}
-
- _C2BlockPoolData(uint32_t id, native_handle_t *handle)
- : mId(id), mHandle(handle) {}
-
- ~_C2BlockPoolData() {
- if (mHandle != NULL) {
- native_handle_close(mHandle);
- native_handle_delete(mHandle);
- }
- }
-};
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::kSynchronizedReadWrite;
-
-typedef uint32_t BufferId;
-typedef uint64_t TransactionId;
-typedef int64_t ConnectionId;
-
-typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
-typedef BufferStatusQueue::Descriptor QueueDescriptor;
-
-/**
- * Allocation wrapper class for buffer pool.
- */
-struct BufferPoolAllocation {
- const native_handle_t *mHandle;
-
- const native_handle_t *handle() {
- return mHandle;
- }
-
- BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
-
- ~BufferPoolAllocation() {};
-};
-
-/**
- * Allocator wrapper class for buffer pool.
- */
-class BufferPoolAllocator {
-public:
-
- /**
- * Allocate an allocation(buffer) for bufer pool.
- *
- * @param params allocation parameters
- * @param alloc created allocation
- *
- * @return OK when an allocation is created successfully.
- */
- virtual ResultStatus allocate(
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc) = 0;
-
- /**
- * Returns whether allocation parameters of an old allocation are
- * compatible with new allocation parameters.
- */
- virtual bool compatible(const std::vector<uint8_t> &newParams,
- const std::vector<uint8_t> &oldParams) = 0;
-
-protected:
- BufferPoolAllocator() = default;
-
- virtual ~BufferPoolAllocator() = default;
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h b/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
deleted file mode 100644
index f91f46b..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
-#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
-
-#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <memory>
-#include <BufferPoolTypes.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::media::bufferpool::V1_0::IAccessor;
-using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct ClientManager : public IClientManager {
- // Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
- Return<void> registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) override;
-
- /** Gets an instance. */
- static sp<ClientManager> getInstance();
-
- /**
- * Creates a local connection with a newly created buffer pool.
- *
- * @param allocator for new buffer allocation.
- * @param pConnectionId Id of the created connection. This is
- * system-wide unique.
- *
- * @return OK when a buffer pool and a local connection is successfully
- * created.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
- ConnectionId *pConnectionId);
-
- /**
- * Closes the specified connection.
- *
- * @param connectionId The id of the connection.
- *
- * @return OK when the connection is closed.
- * NOT_FOUND when the specified connection was not found.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus close(ConnectionId connectionId);
-
- /**
- * Allocates a buffer from the specified connection.
- *
- * @param connectionId The id of the connection.
- * @param params The allocation parameters.
- * @param buffer The allocated buffer.
- *
- * @return OK when a buffer was allocated successfully.
- * NOT_FOUND when the specified connection was not found.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus allocate(ConnectionId connectionId,
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- /**
- * Receives a buffer for the transaction.
- *
- * @param connectionId The id of the receiving connection.
- * @param transactionId The id for the transaction.
- * @param bufferId The id for the buffer.
- * @param timestampUs The timestamp of the buffer is being sent.
- * @param buffer The received buffer.
- *
- * @return OK when a buffer was received successfully.
- * NOT_FOUND when the specified connection was not found.
- * NO_MEMORY when there is no memory.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus receive(ConnectionId connectionId,
- TransactionId transactionId,
- BufferId bufferId,
- int64_t timestampUs,
- std::shared_ptr<_C2BlockPoolData> *buffer);
-
- /**
- * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
- * to other remote clients(connection) after this call has been succeeded.
- *
- * @param connectionId The id of the sending connection.
- * @param receiverId The id of the receiving connection.
- * @param buffer to transfer
- * @param transactionId Id of the transfer transaction.
- * @param timestampUs The timestamp of the buffer transaction is being
- * posted.
- *
- * @return OK when a buffer transaction was posted successfully.
- * NOT_FOUND when the sending connection was not found.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus postSend(ConnectionId connectionId,
- ConnectionId receiverId,
- const std::shared_ptr<_C2BlockPoolData> &buffer,
- TransactionId *transactionId,
- int64_t *timestampUs);
-
- /** Gets a buffer pool for the specified connection.
- *
- * @param connectionId The id of the connection.
- * @param accessor The buffer pool for the specified connection.
- * @return OK when a buffer pool was found for the connection.
- * NOT_FOUND when the specified connection was not found.
- * CRITICAL_ERROR otherwise.
- */
- ResultStatus getAccessor(ConnectionId connectionId,
- sp<IAccessor> *accessor);
-
- /** Destructs the manager of buffer pool clients. */
- ~ClientManager();
-private:
- static sp<ClientManager> sInstance;
- static std::mutex sInstanceLock;
-
- class Impl;
- const std::unique_ptr<Impl> mImpl;
-
- ClientManager();
-};
-
-// FIXME: most likely delete, this is only for passthrough implementations
-// extern "C" IClientManager* HIDL_FETCH_IClientManager(const char* name);
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferpool
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
deleted file mode 100644
index 62286f3..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-cc_test {
- name: "VtsVndkHidlBufferpoolV1_0TargetSingleTest",
- defaults: ["VtsHalTargetTestDefaults"],
- srcs: [
- "allocator.cpp",
- "single.cpp",
- ],
- static_libs: [
- "android.hardware.media.bufferpool@1.0",
- "libion",
- "libstagefright_bufferpool@1.0",
- ],
- shared_libs: [
- "libfmq",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- ],
- compile_multilib: "both",
-}
-
-cc_test {
- name: "VtsVndkHidlBufferpoolV1_0TargetMultiTest",
- defaults: ["VtsHalTargetTestDefaults"],
- srcs: [
- "allocator.cpp",
- "multi.cpp",
- ],
- static_libs: [
- "android.hardware.media.bufferpool@1.0",
- "libion",
- "libstagefright_bufferpool@1.0",
- ],
- shared_libs: [
- "libfmq",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- ],
- compile_multilib: "both",
-}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS b/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS
deleted file mode 100644
index 4c3f7a1..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-# Media team
-taklee@google.com
-lajos@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp
deleted file mode 100644
index 230ee3f..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <C2Buffer.h>
-#include "allocator.h"
-
-union Params {
- struct {
- uint32_t capacity;
- C2MemoryUsage usage;
- } data;
- uint8_t array[0];
- Params() : data{0, {0, 0}} {}
- Params(uint32_t size)
- : data{size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
-};
-
-struct AllocationDtor {
- AllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
- : mAlloc(alloc) {}
-
- void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
-
- const std::shared_ptr<C2LinearAllocation> mAlloc;
-};
-
-ResultStatus VtsBufferPoolAllocator::allocate(
- const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc) {
- Params ionParams;
- memcpy(&ionParams, params.data(), std::min(sizeof(Params), params.size()));
-
- std::shared_ptr<C2LinearAllocation> linearAlloc;
- c2_status_t status = mAllocator->newLinearAllocation(
- ionParams.data.capacity, ionParams.data.usage, &linearAlloc);
- if (status == C2_OK && linearAlloc) {
- BufferPoolAllocation *ptr = new BufferPoolAllocation(linearAlloc->handle());
- if (ptr) {
- *alloc = std::shared_ptr<BufferPoolAllocation>(
- ptr, AllocationDtor(linearAlloc));
- if (*alloc) {
- return ResultStatus::OK;
- }
- delete ptr;
- return ResultStatus::NO_MEMORY;
- }
- }
- return ResultStatus::CRITICAL_ERROR;
-}
-
-bool VtsBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
- const std::vector<uint8_t> &oldParams) {
- size_t newSize = newParams.size();
- size_t oldSize = oldParams.size();
- if (newSize == oldSize) {
- for (size_t i = 0; i < newSize; ++i) {
- if (newParams[i] != oldParams[i]) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
-
-void getVtsAllocatorParams(std::vector<uint8_t> *params) {
- constexpr static int kAllocationSize = 1024 * 10;
- Params ionParams(kAllocationSize);
-
- params->assign(ionParams.array, ionParams.array + sizeof(ionParams));
-}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h
deleted file mode 100644
index 2fbb7fb..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
-#define VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
-
-#include <BufferPoolTypes.h>
-
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::
- BufferPoolAllocation;
-using android::hardware::media::bufferpool::V1_0::implementation::
- BufferPoolAllocator;
-
-// buffer allocator for the tests
-class VtsBufferPoolAllocator : public BufferPoolAllocator {
- public:
- VtsBufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
- : mAllocator(allocator) {}
-
- ~VtsBufferPoolAllocator() override {}
-
- ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc) override;
-
- bool compatible(const std::vector<uint8_t> &newParams,
- const std::vector<uint8_t> &oldParams) override;
-
- private:
- const std::shared_ptr<C2Allocator> mAllocator;
-};
-
-// retrieve buffer allocator paramters
-void getVtsAllocatorParams(std::vector<uint8_t> *params);
-
-#endif // VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
deleted file mode 100644
index 35127b8..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2018 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_TAG "buffferpool_unit_test"
-
-#include <gtest/gtest.h>
-
-#include <C2AllocatorIon.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-#include <ClientManager.h>
-#include <android-base/logging.h>
-#include <binder/ProcessState.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/LegacySupport.h>
-#include <hidl/Status.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <iostream>
-#include <memory>
-#include <vector>
-#include "allocator.h"
-
-using android::C2AllocatorIon;
-using android::C2PlatformAllocatorStore;
-using android::hardware::configureRpcThreadpool;
-using android::hardware::hidl_handle;
-using android::hardware::media::bufferpool::V1_0::IAccessor;
-using android::hardware::media::bufferpool::V1_0::IClientManager;
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
-using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
-using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
-
-namespace {
-
-// communication message types between processes.
-enum PipeCommand : int32_t {
- INIT_OK = 0,
- INIT_ERROR,
- SEND,
- RECEIVE_OK,
- RECEIVE_ERROR,
-};
-
-// communication message between processes.
-union PipeMessage {
- struct {
- int32_t command;
- BufferId bufferId;
- ConnectionId connectionId;
- TransactionId transactionId;
- int64_t timestampUs;
- } data;
- char array[0];
-};
-
-// media.bufferpool test setup
-class BufferpoolMultiTest : public ::testing::Test {
- public:
- virtual void SetUp() override {
- ResultStatus status;
- mReceiverPid = -1;
-
- ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
- ASSERT_TRUE(pipe(mResultPipeFds) == 0);
-
- mReceiverPid = fork();
- ASSERT_TRUE(mReceiverPid >= 0);
-
- if (mReceiverPid == 0) {
- doReceiver();
- return;
- }
-
- mManager = ClientManager::getInstance();
- ASSERT_NE(mManager, nullptr);
-
- std::shared_ptr<C2Allocator> allocator =
- std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
- ASSERT_TRUE((bool)allocator);
-
- mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
- ASSERT_TRUE((bool)mAllocator);
-
- status = mManager->create(mAllocator, &mConnectionId);
- ASSERT_TRUE(status == ResultStatus::OK);
-
- status = mManager->getAccessor(mConnectionId, &mAccessor);
- ASSERT_TRUE(status == ResultStatus::OK && (bool)mAccessor);
- }
-
- virtual void TearDown() override {
- if (mReceiverPid > 0) {
- kill(mReceiverPid, SIGKILL);
- int wstatus;
- wait(&wstatus);
- }
- }
-
- protected:
- static void description(const std::string& description) {
- RecordProperty("description", description);
- }
-
- android::sp<ClientManager> mManager;
- android::sp<IAccessor> mAccessor;
- std::shared_ptr<BufferPoolAllocator> mAllocator;
- ConnectionId mConnectionId;
- pid_t mReceiverPid;
- int mCommandPipeFds[2];
- int mResultPipeFds[2];
-
- bool sendMessage(int *pipes, const PipeMessage &message) {
- int ret = write(pipes[1], message.array, sizeof(PipeMessage));
- return ret == sizeof(PipeMessage);
- }
-
- bool receiveMessage(int *pipes, PipeMessage *message) {
- int ret = read(pipes[0], message->array, sizeof(PipeMessage));
- return ret == sizeof(PipeMessage);
- }
-
- void doReceiver() {
- configureRpcThreadpool(1, false);
- PipeMessage message;
- mManager = ClientManager::getInstance();
- if (!mManager) {
- message.data.command = PipeCommand::INIT_ERROR;
- sendMessage(mResultPipeFds, message);
- return;
- }
- android::status_t status = mManager->registerAsService();
- if (status != android::OK) {
- message.data.command = PipeCommand::INIT_ERROR;
- sendMessage(mResultPipeFds, message);
- return;
- }
- message.data.command = PipeCommand::INIT_OK;
- sendMessage(mResultPipeFds, message);
-
- receiveMessage(mCommandPipeFds, &message);
- {
- std::shared_ptr<_C2BlockPoolData> rbuffer;
- ResultStatus status = mManager->receive(
- message.data.connectionId, message.data.transactionId,
- message.data.bufferId, message.data.timestampUs, &rbuffer);
- if (status != ResultStatus::OK) {
- message.data.command = PipeCommand::RECEIVE_ERROR;
- sendMessage(mResultPipeFds, message);
- return;
- }
- }
- message.data.command = PipeCommand::RECEIVE_OK;
- sendMessage(mResultPipeFds, message);
- while(1); // An easy way to ignore gtest behaviour.
- }
-};
-
-// Buffer transfer test between processes.
-TEST_F(BufferpoolMultiTest, TransferBuffer) {
- ResultStatus status;
- PipeMessage message;
-
- ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
-
- android::sp<IClientManager> receiver = IClientManager::getService();
- ConnectionId receiverId;
- ASSERT_TRUE((bool)receiver);
-
- receiver->registerSender(
- mAccessor, [&status, &receiverId]
- (ResultStatus outStatus, ConnectionId outId) {
- status = outStatus;
- receiverId = outId;
- });
- ASSERT_TRUE(status == ResultStatus::OK);
- {
- std::shared_ptr<_C2BlockPoolData> sbuffer;
- TransactionId transactionId;
- int64_t postUs;
- std::vector<uint8_t> vecParams;
-
- getVtsAllocatorParams(&vecParams);
- status = mManager->allocate(mConnectionId, vecParams, &sbuffer);
- ASSERT_TRUE(status == ResultStatus::OK);
-
- status = mManager->postSend(mConnectionId, receiverId, sbuffer,
- &transactionId, &postUs);
- ASSERT_TRUE(status == ResultStatus::OK);
-
- message.data.command = PipeCommand::SEND;
- message.data.bufferId = sbuffer->mId;
- message.data.connectionId = receiverId;
- message.data.transactionId = transactionId;
- message.data.timestampUs = postUs;
- sendMessage(mCommandPipeFds, message);
- }
- EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
-}
-
-} // anonymous namespace
-
-int main(int argc, char** argv) {
- setenv("TREBLE_TESTING_OVERRIDE", "true", true);
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
deleted file mode 100644
index c8878f3..0000000
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2018 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_TAG "buffferpool_unit_test"
-
-#include <gtest/gtest.h>
-
-#include <C2AllocatorIon.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-#include <ClientManager.h>
-#include <android-base/logging.h>
-#include <binder/ProcessState.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/LegacySupport.h>
-#include <hidl/Status.h>
-#include <unistd.h>
-#include <iostream>
-#include <memory>
-#include <vector>
-#include "allocator.h"
-
-using android::C2AllocatorIon;
-using android::C2PlatformAllocatorStore;
-using android::hardware::hidl_handle;
-using android::hardware::media::bufferpool::V1_0::IAccessor;
-using android::hardware::media::bufferpool::V1_0::ResultStatus;
-using android::hardware::media::bufferpool::V1_0::implementation::BufferId;
-using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
-using android::hardware::media::bufferpool::V1_0::implementation::TransactionId;
-
-namespace {
-
-// Number of iteration for buffer allocation test.
-constexpr static int kNumAllocationTest = 3;
-
-// Number of iteration for buffer recycling test.
-constexpr static int kNumRecycleTest = 3;
-
-// media.bufferpool test setup
-class BufferpoolSingleTest : public ::testing::Test {
- public:
- virtual void SetUp() override {
- ResultStatus status;
-
- mManager = ClientManager::getInstance();
- ASSERT_NE(mManager, nullptr);
-
- std::shared_ptr<C2Allocator> allocator =
- std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
- ASSERT_TRUE((bool)allocator);
-
- mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
- ASSERT_TRUE((bool)mAllocator);
-
- status = mManager->create(mAllocator, &mConnectionId);
- ASSERT_TRUE(status == ResultStatus::OK);
-
- status = mManager->getAccessor(mConnectionId, &mAccessor);
- ASSERT_TRUE(status == ResultStatus::OK && (bool)mAccessor);
-
- ConnectionId& receiverId = mReceiverId;
- mManager->registerSender(
- mAccessor,
- [&status, &receiverId](ResultStatus hidlStatus, ConnectionId hidlId) {
- status = hidlStatus;
- receiverId = hidlId;
- });
- ASSERT_TRUE(status == ResultStatus::ALREADY_EXISTS &&
- receiverId == mConnectionId);
- }
-
- protected:
- static void description(const std::string& description) {
- RecordProperty("description", description);
- }
-
- android::sp<ClientManager> mManager;
- android::sp<IAccessor> mAccessor;
- std::shared_ptr<BufferPoolAllocator> mAllocator;
- ConnectionId mConnectionId;
- ConnectionId mReceiverId;
-
-};
-
-// Buffer allocation test.
-// Check whether each buffer allocation is done successfully with
-// unique buffer id.
-TEST_F(BufferpoolSingleTest, AllocateBuffer) {
- ResultStatus status;
- std::vector<uint8_t> vecParams;
- getVtsAllocatorParams(&vecParams);
-
- std::shared_ptr<_C2BlockPoolData> buffer[kNumAllocationTest];
- for (int i = 0; i < kNumAllocationTest; ++i) {
- status = mManager->allocate(mConnectionId, vecParams, &buffer[i]);
- ASSERT_TRUE(status == ResultStatus::OK);
- }
- for (int i = 0; i < kNumAllocationTest; ++i) {
- for (int j = i + 1; j < kNumAllocationTest; ++j) {
- ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
- }
- }
- EXPECT_TRUE(kNumAllocationTest > 1);
-}
-
-// Buffer recycle test.
-// Check whether de-allocated buffers are recycled.
-TEST_F(BufferpoolSingleTest, RecycleBuffer) {
- ResultStatus status;
- std::vector<uint8_t> vecParams;
- getVtsAllocatorParams(&vecParams);
-
- BufferId bid[kNumRecycleTest];
- for (int i = 0; i < kNumRecycleTest; ++i) {
- std::shared_ptr<_C2BlockPoolData> buffer;
- status = mManager->allocate(mConnectionId, vecParams, &buffer);
- ASSERT_TRUE(status == ResultStatus::OK);
- bid[i] = buffer->mId;
- }
- for (int i = 1; i < kNumRecycleTest; ++i) {
- ASSERT_TRUE(bid[i - 1] == bid[i]);
- }
- EXPECT_TRUE(kNumRecycleTest > 1);
-}
-
-// Buffer transfer test.
-// Check whether buffer is transferred to another client successfully.
-TEST_F(BufferpoolSingleTest, TransferBuffer) {
- ResultStatus status;
- std::vector<uint8_t> vecParams;
- getVtsAllocatorParams(&vecParams);
- std::shared_ptr<_C2BlockPoolData> sbuffer, rbuffer;
-
- TransactionId transactionId;
- int64_t postUs;
-
- status = mManager->allocate(mConnectionId, vecParams, &sbuffer);
- ASSERT_TRUE(status == ResultStatus::OK);
- status = mManager->postSend(mConnectionId, mReceiverId, sbuffer,
- &transactionId, &postUs);
- ASSERT_TRUE(status == ResultStatus::OK);
- status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postUs,
- &rbuffer);
- EXPECT_TRUE(status == ResultStatus::OK);
-}
-
-} // anonymous namespace
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
deleted file mode 100644
index 8d28192..0000000
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
-#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
-
-#include <functional>
-
-#include <C2Buffer.h>
-
-namespace android {
-
-/**
- * Unwrap the native handle from a Codec2 handle allocated by C2AllocatorGralloc.
- *
- * @param handle a handle allocated by C2AllocatorGralloc. This includes handles returned for a
- * graphic block allocation handle returned.
- *
- * @return a new NON-OWNING native handle that must be deleted using native_handle_delete.
- */
-native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle);
-
-/**
- * Wrap the gralloc handle and metadata into Codec2 handle recognized by
- * C2AllocatorGralloc.
- *
- * @return a new NON-OWNING C2Handle that must be deleted using native_handle_delete.
- */
-C2Handle *WrapNativeCodec2GrallocHandle(
- const native_handle_t *const handle,
- uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride);
-
-class C2AllocatorGralloc : public C2Allocator {
-public:
- virtual id_t getId() const override;
-
- virtual C2String getName() const override;
-
- virtual std::shared_ptr<const Traits> getTraits() const override;
-
- virtual c2_status_t newGraphicAllocation(
- uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
- virtual c2_status_t priorGraphicAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
- C2AllocatorGralloc(id_t id);
-
- c2_status_t status() const;
-
- virtual ~C2AllocatorGralloc() override;
-
- static bool isValid(const C2Handle* const o);
-
-private:
- class Impl;
- Impl *mImpl;
-};
-
-} // namespace android
-
-#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
deleted file mode 100644
index 8c0992e..0000000
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
-#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
-
-#include <functional>
-
-#include <C2Buffer.h>
-
-namespace android {
-
-class C2AllocatorIon : public C2Allocator {
-public:
- // (usage, capacity) => (align, heapMask, flags)
- typedef std::function<int (C2MemoryUsage, size_t,
- /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
- virtual id_t getId() const override;
-
- virtual C2String getName() const override;
-
- virtual std::shared_ptr<const Traits> getTraits() const override;
-
- virtual c2_status_t newLinearAllocation(
- uint32_t capacity, C2MemoryUsage usage,
- std::shared_ptr<C2LinearAllocation> *allocation) override;
-
- virtual c2_status_t priorLinearAllocation(
- const C2Handle *handle,
- std::shared_ptr<C2LinearAllocation> *allocation) override;
-
- C2AllocatorIon(id_t id);
-
- virtual c2_status_t status() const { return mInit; }
-
- virtual ~C2AllocatorIon() override;
-
- static bool isValid(const C2Handle* const o);
-
-private:
- std::shared_ptr<const Traits> mTraits;
- c2_status_t mInit;
- int mIonFd;
- usage_mapper_fn mUsageMapper;
-};
-
-} // namespace android
-
-#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
deleted file mode 100644
index 211c13a..0000000
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
-#define STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
-
-#include <functional>
-
-#include <C2Buffer.h>
-
-class C2BasicLinearBlockPool : public C2BlockPool {
-public:
- explicit C2BasicLinearBlockPool(const std::shared_ptr<C2Allocator> &allocator);
-
- virtual ~C2BasicLinearBlockPool() override = default;
-
- virtual C2Allocator::id_t getAllocatorId() const override {
- return mAllocator->getId();
- }
-
- virtual local_id_t getLocalId() const override {
- return BASIC_LINEAR;
- }
-
- virtual c2_status_t fetchLinearBlock(
- uint32_t capacity,
- C2MemoryUsage usage,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
-
- // TODO: fetchCircularBlock
-
-private:
- const std::shared_ptr<C2Allocator> mAllocator;
-};
-
-class C2BasicGraphicBlockPool : public C2BlockPool {
-public:
- explicit C2BasicGraphicBlockPool(const std::shared_ptr<C2Allocator> &allocator);
-
- virtual ~C2BasicGraphicBlockPool() override = default;
-
- virtual C2Allocator::id_t getAllocatorId() const override {
- return mAllocator->getId();
- }
-
- virtual local_id_t getLocalId() const override {
- return BASIC_GRAPHIC;
- }
-
- virtual c2_status_t fetchGraphicBlock(
- uint32_t width,
- uint32_t height,
- uint32_t format,
- C2MemoryUsage usage,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
-
-private:
- const std::shared_ptr<C2Allocator> mAllocator;
-};
-
-class C2PooledBlockPool : public C2BlockPool {
-public:
- C2PooledBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
-
- virtual ~C2PooledBlockPool() override;
-
- virtual C2Allocator::id_t getAllocatorId() const override {
- return mAllocator->getId();
- }
-
- virtual local_id_t getLocalId() const override {
- return mLocalId;
- }
-
- virtual c2_status_t fetchLinearBlock(
- uint32_t capacity,
- C2MemoryUsage usage,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
-
- // TODO: fetchGraphicBlock, fetchCircularBlock
-private:
- const std::shared_ptr<C2Allocator> mAllocator;
- const local_id_t mLocalId;
-
- class Impl;
- std::unique_ptr<Impl> mImpl;
-};
-
-#endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
deleted file mode 100644
index f6d8b98..0000000
--- a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
-#define STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
-
-#include <C2Component.h>
-
-#include <functional>
-#include <memory>
-
-/**
- * Component factory object that enables to create a component and/or interface from a dynamically
- * linked library. This is needed because the component/interfaces are managed objects, but we
- * cannot safely create a managed object and pass it in C.
- *
- * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
- * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
- * derives from enable_shared_from_this.
- *
- */
-class C2ComponentFactory {
-public:
- typedef std::function<void(::C2Component*)> ComponentDeleter;
- typedef std::function<void(::C2ComponentInterface*)> InterfaceDeleter;
-
- /**
- * Creates a component.
- *
- * This method SHALL return within 100ms.
- *
- * \param id component ID for the created component
- * \param component shared pointer where the created component is stored. Cleared on
- * failure and updated on success.
- *
- * \retval C2_OK the component was created successfully
- * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
- *
- * \retval C2_NO_MEMORY not enough memory to create the component
- */
- virtual c2_status_t createComponent(
- c2_node_id_t id, std::shared_ptr<C2Component>* const component,
- ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
-
- /**
- * Creates a component interface.
- *
- * This method SHALL return within 100ms.
- *
- * \param id component interface ID for the created interface
- * \param interface shared pointer where the created interface is stored. Cleared on
- * failure and updated on success.
- *
- * \retval C2_OK the component interface was created successfully
- * \retval C2_TIMED_OUT could not create the component interface within the time limit
- * (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
- * (unexpected)
- *
- * \retval C2_NO_MEMORY not enough memory to create the component interface
- */
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
- InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
-
- virtual ~C2ComponentFactory() = default;
-
- typedef ::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
- typedef void (*DestroyCodec2FactoryFunc)(::C2ComponentFactory*);
-};
-
-
-#endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
deleted file mode 100644
index 5b995f6..0000000
--- a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
-#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
-
-#include <errno.h>
-#include <C2.h>
-
-// standard ERRNO mappings
-template<int N> constexpr c2_status_t _c2_errno2status_impl();
-template<> constexpr c2_status_t _c2_errno2status_impl<0>() { return C2_OK; }
-template<> constexpr c2_status_t _c2_errno2status_impl<EINVAL>() { return C2_BAD_VALUE; }
-template<> constexpr c2_status_t _c2_errno2status_impl<EACCES>() { return C2_REFUSED; }
-template<> constexpr c2_status_t _c2_errno2status_impl<EPERM>() { return C2_REFUSED; }
-template<> constexpr c2_status_t _c2_errno2status_impl<ENOMEM>() { return C2_NO_MEMORY; }
-
-// map standard errno-s to the equivalent c2_status_t
-template<int... N> struct _c2_map_errno_impl;
-template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
- static c2_status_t map(int result) {
- if (result == E) {
- return _c2_errno2status_impl <E>();
- } else {
- return _c2_map_errno_impl<N...>::map(result);
- }
- }
-};
-template<> struct _c2_map_errno_impl<> {
- static c2_status_t map(int result) {
- return result == 0 ? C2_OK : C2_CORRUPTED;
- }
-};
-
-template<int... N>
-c2_status_t c2_map_errno(int result) {
- return _c2_map_errno_impl<N...>::map(result);
-}
-
-#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
-
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
deleted file mode 100644
index 211ee0c..0000000
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
-#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
-
-#include <C2Component.h>
-#include <C2ComponentFactory.h>
-
-#include <memory>
-
-namespace android {
-
-/**
- * Returns the platform allocator store.
- * \retval nullptr if the platform allocator store could not be obtained
- */
-std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
-
-/**
- * Platform allocator store IDs
- */
-class C2PlatformAllocatorStore : public C2AllocatorStore {
-public:
- enum : id_t {
- /**
- * ID of the ion backed platform allocator.
- *
- * C2Handle consists of:
- * fd shared ion buffer handle
- * int size (lo 32 bits)
- * int size (hi 32 bits)
- * int magic '\xc2io\x00'
- */
- ION = PLATFORM_START,
-
- /**
- * ID of the gralloc backed platform allocator.
- *
- * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
- * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
- * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
- */
- GRALLOC,
- };
-};
-
-/**
- * Retrieves a block pool for a component.
- *
- * \param id the local ID of the block pool
- * \param component the component using the block pool (must be non-null)
- * \param pool pointer to where the obtained block pool shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_BAD_VALUE the component is null
- * \retval C2_NOT_FOUND if the block pool does not exist
- * \retval C2_NO_MEMORY not enough memory to fetch the block pool (this return value is only
- * possible for basic pools)
- * \retval C2_TIMED_OUT the operation timed out (this return value is only possible for basic pools)
- * \retval C2_REFUSED no permission to complete any required allocation (this return value is only
- * possible for basic pools)
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected,
- * this return value is only possible for basic pools)
- */
-c2_status_t GetCodec2BlockPool(
- C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
- std::shared_ptr<C2BlockPool> *pool);
-
-/**
- * Creates a block pool.
- * \param allocatorId the allocator ID which is used to allocate blocks
- * \param component the component using the block pool (must be non-null)
- * \param pool pointer to where the created block pool shall be store on success.
- * nullptr will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_BAD_VALUE the component is null
- * \retval C2_NOT_FOUND if the allocator does not exist
- * \retval C2_NO_MEMORY not enough memory to create a block pool
- */
-c2_status_t CreateCodec2BlockPool(
- C2PlatformAllocatorStore::id_t allocatorId,
- std::shared_ptr<const C2Component> component,
- std::shared_ptr<C2BlockPool> *pool);
-
-/**
- * Returns the platform component store.
- * \retval nullptr if the platform component store could not be obtained
- */
-std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
-
-} // namespace android
-
-#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
deleted file mode 100644
index 710e74b..0000000
--- a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2UTILS_PARAM_UTILS_H_
-#define C2UTILS_PARAM_UTILS_H_
-
-#include <C2Param.h>
-#include <util/_C2MacroUtils.h>
-
-#include <iostream>
-#include <list>
-#include <utility>
-#include <vector>
-
-/** \file
- * Utilities for parameter handling to be used by Codec2 implementations.
- */
-
-/// \cond INTERNAL
-
-/* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
-
-/**
- * Utility class that allows ignoring enum value assignment (e.g. both '(_C2EnumConst)kValue = x'
- * and '(_C2EnumConst)kValue' will eval to kValue.
- */
-template<typename T>
-class _C2EnumConst {
-public:
- // implicit conversion from T
- inline _C2EnumConst(T value) : _mValue(value) {}
- // implicit conversion to T
- inline operator T() { return _mValue; }
- // implicit conversion to C2Value::Primitive
- inline operator C2Value::Primitive() { return (T)_mValue; }
- // ignore assignment and return T here to avoid implicit conversion to T later
- inline T &operator =(T value __unused) { return _mValue; }
-private:
- T _mValue;
-};
-
-/// mapper to get name of enum
-/// \note this will contain any initialization, which we will remove when converting to lower-case
-#define _C2_GET_ENUM_NAME(x, y) #x
-/// mapper to get value of enum
-#define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x
-
-/// \endcond
-
-#undef DEFINE_C2_ENUM_VALUE_AUTO_HELPER
-#define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
-template<> C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
- return C2ParamUtils::sanitizeEnumValues( \
- std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
- { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
- prefix); \
-}
-
-#undef DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER
-#define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, ...) \
-template<> C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
- return C2ParamUtils::customEnumValues( \
- std::vector<std::pair<C2StringLiteral, name>> names); \
-}
-
-
-class C2ParamUtils {
-private:
- static size_t countLeadingUnderscores(C2StringLiteral a) {
- size_t i = 0;
- while (a[i] == '_') {
- ++i;
- }
- return i;
- }
-
- static size_t countMatching(C2StringLiteral a, const C2String &b) {
- for (size_t i = 0; i < b.size(); ++i) {
- if (!a[i] || a[i] != b[i]) {
- return i;
- }
- }
- return b.size();
- }
-
- // ABCDef => abc-def
- // ABCD2ef => abcd2-ef // 0
- // ABCD2Ef => ancd2-ef // -1
- // AbcDef => abc-def // -1
- // Abc2Def => abc-2def
- // Abc2def => abc-2-def
- // _Yo => _yo
- // _yo => _yo
- // C2_yo => c2-yo
- // C2__yo => c2-yo
-
- static C2String camelCaseToDashed(C2String name) {
- enum {
- kNone = '.',
- kLower = 'a',
- kUpper = 'A',
- kDigit = '1',
- kDash = '-',
- kUnderscore = '_',
- } type = kNone;
- size_t word_start = 0;
- for (size_t ix = 0; ix < name.size(); ++ix) {
- /* std::cout << name.substr(0, word_start) << "|"
- << name.substr(word_start, ix - word_start) << "["
- << name.substr(ix, 1) << "]" << name.substr(ix + 1)
- << ": " << (char)type << std::endl; */
- if (isupper(name[ix])) {
- if (type == kLower) {
- name.insert(ix++, 1, '-');
- word_start = ix;
- }
- name[ix] = tolower(name[ix]);
- type = kUpper;
- } else if (islower(name[ix])) {
- if (type == kDigit && ix > 0) {
- name.insert(ix++, 1, '-');
- word_start = ix;
- } else if (type == kUpper && ix > word_start + 1) {
- name.insert(ix++ - 1, 1, '-');
- word_start = ix - 1;
- }
- type = kLower;
- } else if (isdigit(name[ix])) {
- if (type == kLower) {
- name.insert(ix++, 1, '-');
- word_start = ix;
- }
- type = kDigit;
- } else if (name[ix] == '_') {
- if (type == kDash) {
- name.erase(ix--, 1);
- } else if (type != kNone && type != kUnderscore) {
- name[ix] = '-';
- type = kDash;
- word_start = ix + 1;
- } else {
- type = kUnderscore;
- word_start = ix + 1;
- }
- } else {
- name.resize(ix);
- }
- }
- // std::cout << "=> " << name << std::endl;
- return name;
- }
-
- static std::vector<C2String> sanitizeEnumValueNames(
- const std::vector<C2StringLiteral> names,
- C2StringLiteral _prefix = NULL) {
- std::vector<C2String> sanitizedNames;
- C2String prefix;
- size_t extraUnderscores = 0;
- bool first = true;
- if (_prefix) {
- extraUnderscores = countLeadingUnderscores(_prefix);
- prefix = _prefix + extraUnderscores;
- first = false;
- // std::cout << "prefix:" << prefix << ", underscores:" << extraUnderscores << std::endl;
- }
-
- // calculate prefix and minimum leading underscores
- for (C2StringLiteral s : names) {
- // std::cout << s << std::endl;
- size_t underscores = countLeadingUnderscores(s);
- if (first) {
- extraUnderscores = underscores;
- prefix = s + underscores;
- first = false;
- } else {
- size_t matching = countMatching(
- s + underscores,
- prefix);
- prefix.resize(matching);
- extraUnderscores = std::min(underscores, extraUnderscores);
- }
- // std::cout << "prefix:" << prefix << ", underscores:" << extraUnderscores << std::endl;
- if (prefix.size() == 0 && extraUnderscores == 0) {
- break;
- }
- }
-
- // we swallow the first underscore after upper case prefixes
- bool upperCasePrefix = true;
- for (size_t i = 0; i < prefix.size(); ++i) {
- if (islower(prefix[i])) {
- upperCasePrefix = false;
- break;
- }
- }
-
- for (C2StringLiteral s : names) {
- size_t underscores = countLeadingUnderscores(s);
- C2String sanitized = C2String(s, underscores - extraUnderscores);
- sanitized.append(s + prefix.size() + underscores +
- (upperCasePrefix && s[prefix.size() + underscores] == '_'));
- sanitizedNames.push_back(camelCaseToDashed(sanitized));
- }
-
- for (C2String s : sanitizedNames) {
- std::cout << s << std::endl;
- }
-
- return sanitizedNames;
- }
-
- friend class C2ParamTest_ParamUtilsTest_Test;
-
-public:
- static std::vector<C2String> parseEnumValuesFromString(C2StringLiteral value) {
- std::vector<C2String> foundNames;
- size_t pos = 0, len = strlen(value);
- do {
- size_t endPos = strcspn(value + pos, " ,=") + pos;
- if (endPos > pos) {
- foundNames.emplace_back(value + pos, endPos - pos);
- }
- if (value[endPos] && value[endPos] != ',') {
- endPos += strcspn(value + endPos, ",");
- }
- pos = strspn(value + endPos, " ,") + endPos;
- } while (pos < len);
- return foundNames;
- }
-
- template<typename T>
- static C2FieldDescriptor::NamedValuesType sanitizeEnumValues(
- std::vector<T> values,
- std::vector<C2StringLiteral> names,
- C2StringLiteral prefix = NULL) {
- C2FieldDescriptor::NamedValuesType namedValues;
- std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix);
- for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) {
- namedValues.emplace_back(sanitizedNames[i], values[i]);
- }
- return namedValues;
- }
-
- template<typename E>
- static C2FieldDescriptor::NamedValuesType customEnumValues(
- std::vector<std::pair<C2StringLiteral, E>> items) {
- C2FieldDescriptor::NamedValuesType namedValues;
- for (auto &item : items) {
- namedValues.emplace_back(item.first, item.second);
- }
- return namedValues;
- }
-
- /// safe(r) parsing from parameter blob
- static
- C2Param *ParseFirst(const uint8_t *blob, size_t size) {
- // _mSize must fit into size, but really C2Param must also to be a valid param
- if (size < sizeof(C2Param)) {
- return nullptr;
- }
- // _mSize must match length
- C2Param *param = (C2Param*)blob;
- if (param->size() > size) {
- return nullptr;
- }
- return param;
- }
-};
-
-/* ---------------------------- UTILITIES FOR PARAMETER REFLECTION ---------------------------- */
-
-/* ======================== UTILITY TEMPLATES FOR PARAMETER REFLECTION ======================== */
-
-#if 1
-template<typename... Params>
-class C2_HIDE _C2Tuple { };
-
-C2_HIDE
-void addC2Params(std::list<const C2FieldDescriptor> &, _C2Tuple<> *) {
-}
-
-template<typename T, typename... Params>
-C2_HIDE
-void addC2Params(std::list<const C2FieldDescriptor> &fields, _C2Tuple<T, Params...> *)
-{
- //C2Param::CodeIndex index = T::CORE_INDEX;
- //(void)index;
- fields.insert(fields.end(), T::FIELD_LIST);
- addC2Params(fields, (_C2Tuple<Params...> *)nullptr);
-}
-
-template<typename... Params>
-C2_HIDE
-std::list<const C2FieldDescriptor> describeC2Params() {
- std::list<const C2FieldDescriptor> fields;
- addC2Params(fields, (_C2Tuple<Params...> *)nullptr);
- return fields;
-}
-
-#endif
-
-/* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
-
-#endif // C2UTILS_PARAM_UTILS_H_
-
diff --git a/media/libstagefright/codec2/vndk/include/util/_C2MacroUtils.h b/media/libstagefright/codec2/vndk/include/util/_C2MacroUtils.h
deleted file mode 100644
index 04e9ba5..0000000
--- a/media/libstagefright/codec2/vndk/include/util/_C2MacroUtils.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef C2UTILS_MACRO_UTILS_H_
-#define C2UTILS_MACRO_UTILS_H_
-
-/** \file
- * Macro utilities for the utils library used by Codec2 implementations.
- */
-
-/// \if 0
-
-/* --------------------------------- VARIABLE ARGUMENT COUNTING --------------------------------- */
-
-// remove empty arguments - _C2_ARG() expands to '', while _C2_ARG(x) expands to ', x'
-// _C2_ARGn(...) does the same for n arguments
-#define _C2_ARG(...) , ##__VA_ARGS__
-#define _C2_ARG2(_1, _2) _C2_ARG(_1) _C2_ARG(_2)
-#define _C2_ARG4(_1, _2, _3, _4) _C2_ARG2(_1, _2) _C2_ARG2(_3, _4)
-#define _C2_ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _C2_ARG4(_1, _2, _3, _4) _C2_ARG4(_5, _6, _7, _8)
-#define _C2_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
- _C2_ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _C2_ARG8(_9, _10, _11, _12, _13, _14, _15, _16)
-
-// return the 65th argument
-#define _C2_ARGC_3(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \
- _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \
- _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, \
- _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) _64
-
-/// \endif
-
-/**
- * Returns the number of arguments.
- */
-// We do this by prepending 1 and appending 65 designed values such that the 65th element
-// will be the number of arguments.
-#define _C2_ARGC(...) _C2_ARGC_1(0, ##__VA_ARGS__, \
- 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, \
- 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
- 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-
-/// \if 0
-
-// step 1. remove empty arguments - this is needed to allow trailing comma in enum definitions
-// (NOTE: we don't know which argument will have this trailing comma so we have to try all)
-#define _C2_ARGC_1(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \
- _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \
- _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, \
- _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) \
- _C2_ARGC_2(_ _C2_ARG(_0) \
- _C2_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
- _C2_ARG16(_17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32) \
- _C2_ARG16(_33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48) \
- _C2_ARG16(_49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64), \
- ##__VA_ARGS__)
-
-// step 2. this is needed as removed arguments cannot be passed directly as empty into a macro
-#define _C2_ARGC_2(...) _C2_ARGC_3(__VA_ARGS__)
-
-/// \endif
-
-/* -------------------------------- VARIABLE ARGUMENT CONVERSION -------------------------------- */
-
-/// \if 0
-
-// macros that convert _1, _2, _3, ... to fn(_1, arg), fn(_2, arg), fn(_3, arg), ...
-#define _C2_MAP_64(fn, arg, head, ...) fn(head, arg), _C2_MAP_63(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_63(fn, arg, head, ...) fn(head, arg), _C2_MAP_62(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_62(fn, arg, head, ...) fn(head, arg), _C2_MAP_61(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_61(fn, arg, head, ...) fn(head, arg), _C2_MAP_60(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_60(fn, arg, head, ...) fn(head, arg), _C2_MAP_59(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_59(fn, arg, head, ...) fn(head, arg), _C2_MAP_58(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_58(fn, arg, head, ...) fn(head, arg), _C2_MAP_57(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_57(fn, arg, head, ...) fn(head, arg), _C2_MAP_56(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_56(fn, arg, head, ...) fn(head, arg), _C2_MAP_55(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_55(fn, arg, head, ...) fn(head, arg), _C2_MAP_54(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_54(fn, arg, head, ...) fn(head, arg), _C2_MAP_53(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_53(fn, arg, head, ...) fn(head, arg), _C2_MAP_52(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_52(fn, arg, head, ...) fn(head, arg), _C2_MAP_51(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_51(fn, arg, head, ...) fn(head, arg), _C2_MAP_50(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_50(fn, arg, head, ...) fn(head, arg), _C2_MAP_49(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_49(fn, arg, head, ...) fn(head, arg), _C2_MAP_48(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_48(fn, arg, head, ...) fn(head, arg), _C2_MAP_47(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_47(fn, arg, head, ...) fn(head, arg), _C2_MAP_46(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_46(fn, arg, head, ...) fn(head, arg), _C2_MAP_45(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_45(fn, arg, head, ...) fn(head, arg), _C2_MAP_44(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_44(fn, arg, head, ...) fn(head, arg), _C2_MAP_43(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_43(fn, arg, head, ...) fn(head, arg), _C2_MAP_42(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_42(fn, arg, head, ...) fn(head, arg), _C2_MAP_41(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_41(fn, arg, head, ...) fn(head, arg), _C2_MAP_40(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_40(fn, arg, head, ...) fn(head, arg), _C2_MAP_39(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_39(fn, arg, head, ...) fn(head, arg), _C2_MAP_38(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_38(fn, arg, head, ...) fn(head, arg), _C2_MAP_37(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_37(fn, arg, head, ...) fn(head, arg), _C2_MAP_36(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_36(fn, arg, head, ...) fn(head, arg), _C2_MAP_35(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_35(fn, arg, head, ...) fn(head, arg), _C2_MAP_34(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_34(fn, arg, head, ...) fn(head, arg), _C2_MAP_33(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_33(fn, arg, head, ...) fn(head, arg), _C2_MAP_32(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_32(fn, arg, head, ...) fn(head, arg), _C2_MAP_31(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_31(fn, arg, head, ...) fn(head, arg), _C2_MAP_30(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_30(fn, arg, head, ...) fn(head, arg), _C2_MAP_29(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_29(fn, arg, head, ...) fn(head, arg), _C2_MAP_28(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_28(fn, arg, head, ...) fn(head, arg), _C2_MAP_27(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_27(fn, arg, head, ...) fn(head, arg), _C2_MAP_26(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_26(fn, arg, head, ...) fn(head, arg), _C2_MAP_25(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_25(fn, arg, head, ...) fn(head, arg), _C2_MAP_24(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_24(fn, arg, head, ...) fn(head, arg), _C2_MAP_23(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_23(fn, arg, head, ...) fn(head, arg), _C2_MAP_22(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_22(fn, arg, head, ...) fn(head, arg), _C2_MAP_21(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_21(fn, arg, head, ...) fn(head, arg), _C2_MAP_20(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_20(fn, arg, head, ...) fn(head, arg), _C2_MAP_19(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_19(fn, arg, head, ...) fn(head, arg), _C2_MAP_18(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_18(fn, arg, head, ...) fn(head, arg), _C2_MAP_17(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_17(fn, arg, head, ...) fn(head, arg), _C2_MAP_16(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_16(fn, arg, head, ...) fn(head, arg), _C2_MAP_15(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_15(fn, arg, head, ...) fn(head, arg), _C2_MAP_14(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_14(fn, arg, head, ...) fn(head, arg), _C2_MAP_13(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_13(fn, arg, head, ...) fn(head, arg), _C2_MAP_12(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_12(fn, arg, head, ...) fn(head, arg), _C2_MAP_11(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_11(fn, arg, head, ...) fn(head, arg), _C2_MAP_10(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_10(fn, arg, head, ...) fn(head, arg), _C2_MAP_9(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_9(fn, arg, head, ...) fn(head, arg), _C2_MAP_8(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_8(fn, arg, head, ...) fn(head, arg), _C2_MAP_7(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_7(fn, arg, head, ...) fn(head, arg), _C2_MAP_6(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_6(fn, arg, head, ...) fn(head, arg), _C2_MAP_5(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_5(fn, arg, head, ...) fn(head, arg), _C2_MAP_4(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_4(fn, arg, head, ...) fn(head, arg), _C2_MAP_3(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_3(fn, arg, head, ...) fn(head, arg), _C2_MAP_2(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_2(fn, arg, head, ...) fn(head, arg), _C2_MAP_1(fn, arg, ##__VA_ARGS__)
-#define _C2_MAP_1(fn, arg, head, ...) fn(head, arg)
-
-/// \endif
-
-/**
- * Maps each argument using another macro x -> fn(x, arg)
- */
-// use wrapper to call the proper mapper based on the number of arguments
-#define _C2_MAP(fn, arg, ...) _C2_MAP__(_C2_ARGC(__VA_ARGS__), fn, arg, ##__VA_ARGS__)
-
-/// \if 0
-
-// evaluate _n so it becomes a number
-#define _C2_MAP__(_n, fn, arg, ...) _C2_MAP_(_n, fn, arg, __VA_ARGS__)
-// call the proper mapper
-#define _C2_MAP_(_n, fn, arg, ...) _C2_MAP_##_n (fn, arg, __VA_ARGS__)
-
-/// \endif
-
-#endif // C2UTILS_MACRO_UTILS_H_
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
deleted file mode 100644
index ff67788..0000000
--- a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
-#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
-
-#include <C2Buffer.h>
-
-struct _C2BlockPoolData;
-
-/**
- * Internal only interface for creating blocks by block pool/buffer passing implementations.
- *
- * \todo this must be hidden
- */
-struct _C2BlockFactory {
- /**
- * Create a linear block from an allocation for an allotted range.
- *
- * @param alloc parent allocation
- * @param data blockpool data
- * @param offset allotted range offset
- * @param size allotted size
- *
- * @return shared pointer to the linear block. nullptr if there was not enough memory to
- * create this block.
- */
- static
- std::shared_ptr<C2LinearBlock> CreateLinearBlock(
- const std::shared_ptr<C2LinearAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
- size_t offset = 0,
- size_t size = ~(size_t)0);
-
- /**
- * Create a graphic block from an allocation for an allotted section.
- *
- * @param alloc parent allocation
- * @param data blockpool data
- * @param crop allotted crop region
- *
- * @return shared pointer to the graphic block. nullptr if there was not enough memory to
- * create this block.
- */
- static
- std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
- const std::shared_ptr<C2GraphicAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
- const C2Rect &allottedCrop = C2Rect(~0u, ~0u));
-};
-
-#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
-
diff --git a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h b/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
deleted file mode 100644
index ba7c5d5..0000000
--- a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
-#define ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
-
-#include <C2Param.h>
-
-struct C2_HIDE _C2ParamInspector {
- inline static uint32_t GetOffset(const C2FieldDescriptor &fd) {
- return fd._mFieldId._mOffset;
- }
-
- inline static uint32_t GetSize(const C2FieldDescriptor &fd) {
- return fd._mFieldId._mSize;
- }
-
- inline static uint32_t GetIndex(const C2ParamField &pf) {
- return pf._mIndex;
- }
-
- inline static uint32_t GetOffset(const C2ParamField &pf) {
- return pf._mFieldId._mOffset;
- }
-
- inline static uint32_t GetSize(const C2ParamField &pf) {
- return pf._mFieldId._mSize;
- }
-
- inline static uint32_t GetAttrib(const C2ParamDescriptor &pd) {
- return pd._mAttrib;
- }
-
- inline static
- C2ParamField CreateParamField(C2Param::Index index, uint32_t offset, uint32_t size) {
- return C2ParamField(index, offset, size);
- }
-
- inline static
- C2ParamField CreateParamField(C2Param::Index index, _C2FieldId field) {
- return C2ParamField(index, field._mOffset, field._mSize);
- }
-
- // expose attributes
- typedef C2ParamDescriptor::attrib_t attrib_t;
-};
-
-#endif // ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
-
diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp
index 9931e2d..7352854 100644
--- a/media/libstagefright/codecs/aacdec/Android.bp
+++ b/media/libstagefright/codecs/aacdec/Android.bp
@@ -1,45 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2aacdec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: [
- "C2SoftAac.cpp",
- "DrcPresModeWrap.cpp",
- ],
-
- cflags: ["-Werror"],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: [
- "libFraunhoferAAC",
- ],
-
- shared_libs: [
- "libcutils",
- "libion",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libutils",
- ],
-}
-
-cc_library_shared {
name: "libstagefright_soft_aacdec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp b/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
deleted file mode 100644
index 6bd15a5..0000000
--- a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
- * Copyright (C) 2017 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 "C2SoftAac"
-#include <utils/Log.h>
-
-#include "C2SoftAac.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/misc.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <numeric>
-
-#define FILEREAD_MAX_LAYERS 2
-
-#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */
-#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
-#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
-// names of properties that can be used to override the default DRC settings
-#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level"
-#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut"
-#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost"
-#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy"
-#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level"
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.aac.decoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatAudio)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_AAC)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-C2SoftAac::C2SoftAac(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mAACDecoder(NULL),
- mStreamInfo(NULL),
- mIsADTS(false),
- mSignalledError(false),
- mOutputDelayRingBuffer(NULL) {
-}
-
-C2SoftAac::~C2SoftAac() {
- onRelease();
-}
-
-c2_status_t C2SoftAac::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-c2_status_t C2SoftAac::onStop() {
- drainDecoder();
- // reset the "configured" state
- mOutputDelayCompensated = 0;
- mOutputDelayRingBufferWritePos = 0;
- mOutputDelayRingBufferReadPos = 0;
- mOutputDelayRingBufferFilled = 0;
- mBuffersInfo.clear();
-
- // To make the codec behave the same before and after a reset, we need to invalidate the
- // streaminfo struct. This does that:
- mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only
-
- mSignalledError = false;
-
- return C2_OK;
-}
-
-void C2SoftAac::onReset() {
- (void)onStop();
-}
-
-void C2SoftAac::onRelease() {
- if (mAACDecoder) {
- aacDecoder_Close(mAACDecoder);
- mAACDecoder = NULL;
- }
- if (mOutputDelayRingBuffer) {
- delete[] mOutputDelayRingBuffer;
- mOutputDelayRingBuffer = NULL;
- }
-}
-
-status_t C2SoftAac::initDecoder() {
- ALOGV("initDecoder()");
- status_t status = UNKNOWN_ERROR;
- mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1);
- if (mAACDecoder != NULL) {
- mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
- if (mStreamInfo != NULL) {
- status = OK;
- }
- }
-
- mOutputDelayCompensated = 0;
- mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax;
- mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize];
- mOutputDelayRingBufferWritePos = 0;
- mOutputDelayRingBufferReadPos = 0;
- mOutputDelayRingBufferFilled = 0;
-
- if (mAACDecoder == NULL) {
- ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code");
- }
-
- //aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, 0);
-
- //init DRC wrapper
- mDrcWrap.setDecoderHandle(mAACDecoder);
- mDrcWrap.submitStreamData(mStreamInfo);
-
- // for streams that contain metadata, use the mobile profile DRC settings unless overridden by platform properties
- // TODO: change the DRC settings depending on audio output device type (HDMI, loadspeaker, headphone)
- char value[PROPERTY_VALUE_MAX];
- // DRC_PRES_MODE_WRAP_DESIRED_TARGET
- if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) {
- unsigned refLevel = atoi(value);
- ALOGV("AAC decoder using desired DRC target reference level of %d instead of %d", refLevel,
- DRC_DEFAULT_MOBILE_REF_LEVEL);
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, refLevel);
- } else {
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, DRC_DEFAULT_MOBILE_REF_LEVEL);
- }
- // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR
- if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) {
- unsigned cut = atoi(value);
- ALOGV("AAC decoder using desired DRC attenuation factor of %d instead of %d", cut,
- DRC_DEFAULT_MOBILE_DRC_CUT);
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, cut);
- } else {
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT);
- }
- // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR
- if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) {
- unsigned boost = atoi(value);
- ALOGV("AAC decoder using desired DRC boost factor of %d instead of %d", boost,
- DRC_DEFAULT_MOBILE_DRC_BOOST);
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, boost);
- } else {
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST);
- }
- // DRC_PRES_MODE_WRAP_DESIRED_HEAVY
- if (property_get(PROP_DRC_OVERRIDE_HEAVY, value, NULL)) {
- unsigned heavy = atoi(value);
- ALOGV("AAC decoder using desried DRC heavy compression switch of %d instead of %d", heavy,
- DRC_DEFAULT_MOBILE_DRC_HEAVY);
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, heavy);
- } else {
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
- }
- // DRC_PRES_MODE_WRAP_ENCODER_TARGET
- if (property_get(PROP_DRC_OVERRIDE_ENC_LEVEL, value, NULL)) {
- unsigned encoderRefLevel = atoi(value);
- ALOGV("AAC decoder using encoder-side DRC reference level of %d instead of %d",
- encoderRefLevel, DRC_DEFAULT_MOBILE_ENC_LEVEL);
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, encoderRefLevel);
- } else {
- mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, DRC_DEFAULT_MOBILE_ENC_LEVEL);
- }
-
- // By default, the decoder creates a 5.1 channel downmix signal.
- // For seven and eight channel input streams, enable 6.1 and 7.1 channel output
- aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1);
-
- return status;
-}
-
-bool C2SoftAac::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) {
- if (numSamples == 0) {
- return true;
- }
- if (outputDelayRingBufferSpaceLeft() < numSamples) {
- ALOGE("RING BUFFER WOULD OVERFLOW");
- return false;
- }
- if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize
- && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos
- || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) {
- // faster memcopy loop without checks, if the preconditions allow this
- for (int32_t i = 0; i < numSamples; i++) {
- mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos++] = samples[i];
- }
-
- if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
- mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
- }
- } else {
- ALOGV("slow C2SoftAac::outputDelayRingBufferPutSamples()");
-
- for (int32_t i = 0; i < numSamples; i++) {
- mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos] = samples[i];
- mOutputDelayRingBufferWritePos++;
- if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
- mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
- }
- }
- }
- mOutputDelayRingBufferFilled += numSamples;
- return true;
-}
-
-int32_t C2SoftAac::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) {
-
- if (numSamples > mOutputDelayRingBufferFilled) {
- ALOGE("RING BUFFER WOULD UNDERRUN");
- return -1;
- }
-
- if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize
- && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos
- || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) {
- // faster memcopy loop without checks, if the preconditions allow this
- if (samples != 0) {
- for (int32_t i = 0; i < numSamples; i++) {
- samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++];
- }
- } else {
- mOutputDelayRingBufferReadPos += numSamples;
- }
- if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
- mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
- }
- } else {
- ALOGV("slow C2SoftAac::outputDelayRingBufferGetSamples()");
-
- for (int32_t i = 0; i < numSamples; i++) {
- if (samples != 0) {
- samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos];
- }
- mOutputDelayRingBufferReadPos++;
- if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
- mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
- }
- }
- }
- mOutputDelayRingBufferFilled -= numSamples;
- return numSamples;
-}
-
-int32_t C2SoftAac::outputDelayRingBufferSamplesAvailable() {
- return mOutputDelayRingBufferFilled;
-}
-
-int32_t C2SoftAac::outputDelayRingBufferSpaceLeft() {
- return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable();
-}
-
-void C2SoftAac::drainRingBuffer(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool,
- bool eos) {
- while (!mBuffersInfo.empty() && outputDelayRingBufferSamplesAvailable()
- >= mStreamInfo->frameSize * mStreamInfo->numChannels) {
- Info &outInfo = mBuffersInfo.front();
- ALOGV("outInfo.frameIndex = %" PRIu64, outInfo.frameIndex);
- int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
-
- int available = outputDelayRingBufferSamplesAvailable();
- int numFrames = outInfo.decodedSizes.size();
- int numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);
- if (available < numSamples) {
- if (eos) {
- numSamples = available;
- } else {
- break;
- }
- }
- ALOGV("%d samples available (%d), or %d frames",
- numSamples, available, numFrames);
- ALOGV("getting %d from ringbuffer", numSamples);
-
- std::shared_ptr<C2LinearBlock> block;
- std::function<void(const std::unique_ptr<C2Work>&)> fillWork =
- [&block, numSamples, pool, this]()
- -> std::function<void(const std::unique_ptr<C2Work>&)> {
- auto fillEmptyWork = [](const std::unique_ptr<C2Work> &work, c2_status_t err) {
- work->result = err;
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
-
- using namespace std::placeholders;
- if (numSamples == 0) {
- return std::bind(fillEmptyWork, _1, C2_OK);
- }
-
- // TODO: error handling, proper usage, etc.
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(
- numSamples * sizeof(int16_t), usage, &block);
- if (err != C2_OK) {
- ALOGD("failed to fetch a linear block (%d)", err);
- mSignalledError = true;
- return std::bind(fillEmptyWork, _1, C2_NO_MEMORY);
- }
- C2WriteView wView = block->map().get();
- // TODO
- INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(wView.data());
- int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
- if (ns != numSamples) {
- ALOGE("not a complete frame of samples available");
- mSignalledError = true;
- return std::bind(fillEmptyWork, _1, C2_CORRUPTED);
- }
- return [buffer = createLinearBuffer(block)](const std::unique_ptr<C2Work> &work) {
- work->result = C2_OK;
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- }();
-
- if (work && work->input.ordinal.frameIndex == c2_cntr64_t(outInfo.frameIndex)) {
- fillWork(work);
- } else {
- finish(outInfo.frameIndex, fillWork);
- }
-
- ALOGV("out timestamp %" PRIu64 " / %u", outInfo.timestamp, block ? block->capacity() : 0);
- mBuffersInfo.pop_front();
- }
-}
-
-void C2SoftAac::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->workletsProcessed = 0u;
- work->result = C2_OK;
- if (mSignalledError) {
- return;
- }
-
- UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
- UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
- UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};
-
- INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
- C2ReadView view = work->input.buffers[0]->data().linearBlocks().front().map().get();
- size_t offset = 0u;
- size_t size = view.capacity();
-
- bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
- bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
-
- //TODO
-#if 0
- if (mInputBufferCount == 0 && !codecConfig) {
- ALOGW("first buffer should have FLAG_CODEC_CONFIG set");
- codecConfig = true;
- }
-#endif
- if (codecConfig) {
- // const_cast because of libAACdec method signature.
- inBuffer[0] = const_cast<UCHAR *>(view.data() + offset);
- inBufferLength[0] = size;
-
- AAC_DECODER_ERROR decoderErr =
- aacDecoder_ConfigRaw(mAACDecoder,
- inBuffer,
- inBufferLength);
-
- if (decoderErr != AAC_DEC_OK) {
- ALOGE("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
- mSignalledError = true;
- // TODO: error
- return;
- }
-
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->worklets.front()->output.buffers.clear();
-
- return;
- }
-
- Info inInfo;
- inInfo.frameIndex = work->input.ordinal.frameIndex.peeku();
- inInfo.timestamp = work->input.ordinal.timestamp.peeku();
- inInfo.bufferSize = size;
- inInfo.decodedSizes.clear();
- while (size > 0u) {
- ALOGV("size = %zu", size);
- if (mIsADTS) {
- size_t adtsHeaderSize = 0;
- // skip 30 bits, aac_frame_length follows.
- // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
-
- const uint8_t *adtsHeader = view.data() + offset;
-
- bool signalError = false;
- if (size < 7) {
- ALOGE("Audio data too short to contain even the ADTS header. "
- "Got %zu bytes.", size);
- hexdump(adtsHeader, size);
- signalError = true;
- } else {
- bool protectionAbsent = (adtsHeader[1] & 1);
-
- unsigned aac_frame_length =
- ((adtsHeader[3] & 3) << 11)
- | (adtsHeader[4] << 3)
- | (adtsHeader[5] >> 5);
-
- if (size < aac_frame_length) {
- ALOGE("Not enough audio data for the complete frame. "
- "Got %zu bytes, frame size according to the ADTS "
- "header is %u bytes.",
- size, aac_frame_length);
- hexdump(adtsHeader, size);
- signalError = true;
- } else {
- adtsHeaderSize = (protectionAbsent ? 7 : 9);
- if (aac_frame_length < adtsHeaderSize) {
- signalError = true;
- } else {
- // const_cast because of libAACdec method signature.
- inBuffer[0] = const_cast<UCHAR *>(adtsHeader + adtsHeaderSize);
- inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
- offset += adtsHeaderSize;
- size -= adtsHeaderSize;
- }
- }
- }
-
- if (signalError) {
- mSignalledError = true;
- // TODO: notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
- return;
- }
- } else {
- // const_cast because of libAACdec method signature.
- inBuffer[0] = const_cast<UCHAR *>(view.data() + offset);
- inBufferLength[0] = size;
- }
-
- // Fill and decode
- bytesValid[0] = inBufferLength[0];
-
- INT prevSampleRate = mStreamInfo->sampleRate;
- INT prevNumChannels = mStreamInfo->numChannels;
-
- aacDecoder_Fill(mAACDecoder,
- inBuffer,
- inBufferLength,
- bytesValid);
-
- // run DRC check
- mDrcWrap.submitStreamData(mStreamInfo);
- mDrcWrap.update();
-
- UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
- size -= inBufferUsedLength;
- offset += inBufferUsedLength;
-
- AAC_DECODER_ERROR decoderErr;
- do {
- if (outputDelayRingBufferSpaceLeft() <
- (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
- ALOGV("skipping decode: not enough space left in ringbuffer");
- break;
- }
-
- int numConsumed = mStreamInfo->numTotalBytes;
- decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
- tmpOutBuffer,
- 2048 * MAX_CHANNEL_COUNT,
- 0 /* flags */);
-
- numConsumed = mStreamInfo->numTotalBytes - numConsumed;
-
- if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
- break;
- }
- inInfo.decodedSizes.push_back(numConsumed);
-
- if (decoderErr != AAC_DEC_OK) {
- ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
- }
-
- if (bytesValid[0] != 0) {
- ALOGE("bytesValid[0] != 0 should never happen");
- mSignalledError = true;
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
- }
-
- size_t numOutBytes =
- mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
-
- if (decoderErr == AAC_DEC_OK) {
- if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
- mStreamInfo->frameSize * mStreamInfo->numChannels)) {
- mSignalledError = true;
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
- return;
- }
- } else {
- ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
-
- memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
-
- if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
- mStreamInfo->frameSize * mStreamInfo->numChannels)) {
- mSignalledError = true;
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
- return;
- }
-
- // Discard input buffer.
- size = 0;
-
- aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-
- // After an error, replace bufferSize with the sum of the
- // decodedSizes to resynchronize the in/out lists.
- inInfo.decodedSizes.pop_back();
- inInfo.bufferSize = std::accumulate(
- inInfo.decodedSizes.begin(), inInfo.decodedSizes.end(), 0);
-
- // fall through
- }
-
- /*
- * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
- * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
- * rate system and the sampling rate in the final output is actually
- * doubled compared with the core AAC decoder sampling rate.
- *
- * Explicit signalling is done by explicitly defining SBR audio object
- * type in the bitstream. Implicit signalling is done by embedding
- * SBR content in AAC extension payload specific to SBR, and hence
- * requires an AAC decoder to perform pre-checks on actual audio frames.
- *
- * Thus, we could not say for sure whether a stream is
- * AAC+/eAAC+ until the first data frame is decoded.
- */
- if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
- // TODO:
-#if 0
- if ((mInputBufferCount > 2) && (mOutputBufferCount <= 1)) {
- ALOGW("Invalid AAC stream");
- mSignalledError = true;
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
- return false;
- }
-#endif
- }
- ALOGV("size = %zu", size);
- } while (decoderErr == AAC_DEC_OK);
- }
-
- int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
-
- mBuffersInfo.push_back(std::move(inInfo));
-
- if (!eos && mOutputDelayCompensated < outputDelay) {
- // discard outputDelay at the beginning
- int32_t toCompensate = outputDelay - mOutputDelayCompensated;
- int32_t discard = outputDelayRingBufferSamplesAvailable();
- if (discard > toCompensate) {
- discard = toCompensate;
- }
- int32_t discarded = outputDelayRingBufferGetSamples(0, discard);
- mOutputDelayCompensated += discarded;
- return;
- }
-
- if (eos) {
- drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
- } else {
- drainRingBuffer(work, pool, false /* not EOS */);
- }
-}
-
-c2_status_t C2SoftAac::drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work) {
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- bool eos = (drainMode == DRAIN_COMPONENT_WITH_EOS);
-
- drainDecoder();
- drainRingBuffer(work, pool, eos);
-
- if (eos) {
- auto fillEmptyWork = [](const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- while (mBuffersInfo.size() > 1u) {
- finish(mBuffersInfo.front().frameIndex, fillEmptyWork);
- mBuffersInfo.pop_front();
- }
- if (work->workletsProcessed == 0u) {
- fillEmptyWork(work);
- }
- mBuffersInfo.clear();
- }
-
- return C2_OK;
-}
-
-c2_status_t C2SoftAac::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- return drainInternal(drainMode, pool, nullptr);
-}
-
-c2_status_t C2SoftAac::onFlush_sm() {
- drainDecoder();
- mBuffersInfo.clear();
-
- int avail;
- while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
- if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) {
- avail = mStreamInfo->frameSize * mStreamInfo->numChannels;
- }
- int32_t ns = outputDelayRingBufferGetSamples(0, avail);
- if (ns != avail) {
- ALOGW("not a complete frame of samples available");
- break;
- }
- }
- mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos;
-
- return C2_OK;
-}
-
-void C2SoftAac::drainDecoder() {
- // flush decoder until outputDelay is compensated
- while (mOutputDelayCompensated > 0) {
- // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC
- INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
-
- // run DRC check
- mDrcWrap.submitStreamData(mStreamInfo);
- mDrcWrap.update();
-
- AAC_DECODER_ERROR decoderErr =
- aacDecoder_DecodeFrame(mAACDecoder,
- tmpOutBuffer,
- 2048 * MAX_CHANNEL_COUNT,
- AACDEC_FLUSH);
- if (decoderErr != AAC_DEC_OK) {
- ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
- }
-
- int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
- if (tmpOutBufferSamples > mOutputDelayCompensated) {
- tmpOutBufferSamples = mOutputDelayCompensated;
- }
- outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
-
- mOutputDelayCompensated -= tmpOutBufferSamples;
- }
-}
-
-class C2SoftAacDecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftAac(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftAacDecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftAacDecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/aacdec/C2SoftAac.h b/media/libstagefright/codecs/aacdec/C2SoftAac.h
deleted file mode 100644
index b877635..0000000
--- a/media/libstagefright/codecs/aacdec/C2SoftAac.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef C2_SOFT_AAC_H_
-#define C2_SOFT_AAC_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-#include "aacdecoder_lib.h"
-#include "DrcPresModeWrap.h"
-
-namespace android {
-
-struct C2SoftAac : public SimpleC2Component {
- C2SoftAac(const char *name, c2_node_id_t id);
- virtual ~C2SoftAac();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- enum {
- kNumDelayBlocksMax = 8,
- };
-
- HANDLE_AACDECODER mAACDecoder;
- CStreamInfo *mStreamInfo;
- bool mIsADTS;
- bool mIsFirst;
- size_t mInputBufferCount;
- size_t mOutputBufferCount;
- bool mSignalledError;
- struct Info {
- uint64_t frameIndex;
- size_t bufferSize;
- uint64_t timestamp;
- std::vector<int32_t> decodedSizes;
- };
- std::list<Info> mBuffersInfo;
-
- CDrcPresModeWrapper mDrcWrap;
-
- enum {
- NONE,
- AWAITING_DISABLED,
- AWAITING_ENABLED
- } mOutputPortSettingsChange;
-
- void initPorts();
- status_t initDecoder();
- bool isConfigured() const;
- void drainDecoder();
-
- void drainRingBuffer(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool,
- bool eos);
- c2_status_t drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work);
-
-// delay compensation
- bool mEndOfInput;
- bool mEndOfOutput;
- int32_t mOutputDelayCompensated;
- int32_t mOutputDelayRingBufferSize;
- short *mOutputDelayRingBuffer;
- int32_t mOutputDelayRingBufferWritePos;
- int32_t mOutputDelayRingBufferReadPos;
- int32_t mOutputDelayRingBufferFilled;
- bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples);
- int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples);
- int32_t outputDelayRingBufferSamplesAvailable();
- int32_t outputDelayRingBufferSpaceLeft();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftAac);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_AAC_H_
diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp
index 9386c6e..9342351 100644
--- a/media/libstagefright/codecs/aacenc/Android.bp
+++ b/media/libstagefright/codecs/aacenc/Android.bp
@@ -1,42 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2aacenc",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftAacEnc.cpp"],
-
- cflags: ["-Werror"],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: [
- "libFraunhoferAAC",
- ],
-
- shared_libs: [
- "libcutils",
- "libion",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libutils",
- ],
-}
-
-cc_library_shared {
name: "libstagefright_soft_aacenc",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
deleted file mode 100644
index 70f6817..0000000
--- a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Copyright (C) 2012 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 "C2SoftAacEnc"
-#include <utils/Log.h>
-
-#include <inttypes.h>
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-#include "C2SoftAacEnc.h"
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.aac.encoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatAudio)
- .outputFormat(C2FormatCompressed)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_AAC)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-C2SoftAacEnc::C2SoftAacEnc(
- const char *name,
- c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mAACEncoder(NULL),
- mNumChannels(1),
- mSampleRate(44100),
- mBitRate(64000),
- mSBRMode(-1),
- mSBRRatio(0),
- mAACProfile(AOT_AAC_LC),
- mNumBytesPerInputFrame(0u),
- mOutBufferSize(0u),
- mSentCodecSpecificData(false),
- mInputSize(0),
- mInputTimeUs(-1ll),
- mSignalledError(false) {
-}
-
-C2SoftAacEnc::~C2SoftAacEnc() {
- onReset();
-}
-
-c2_status_t C2SoftAacEnc::onInit() {
- status_t err = initEncoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-status_t C2SoftAacEnc::initEncoder() {
- if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) {
- ALOGE("Failed to init AAC encoder");
- return UNKNOWN_ERROR;
- }
- return setAudioParams();
-}
-
-c2_status_t C2SoftAacEnc::onStop() {
- mSentCodecSpecificData = false;
- mInputSize = 0u;
- mInputTimeUs = -1ll;
- mSignalledError = false;
- return C2_OK;
-}
-
-void C2SoftAacEnc::onReset() {
- (void)onStop();
- aacEncClose(&mAACEncoder);
-}
-
-void C2SoftAacEnc::onRelease() {
- // no-op
-}
-
-c2_status_t C2SoftAacEnc::onFlush_sm() {
- mSentCodecSpecificData = false;
- mInputSize = 0u;
- return C2_OK;
-}
-
-static CHANNEL_MODE getChannelMode(uint32_t nChannels) {
- CHANNEL_MODE chMode = MODE_INVALID;
- switch (nChannels) {
- case 1: chMode = MODE_1; break;
- case 2: chMode = MODE_2; break;
- case 3: chMode = MODE_1_2; break;
- case 4: chMode = MODE_1_2_1; break;
- case 5: chMode = MODE_1_2_2; break;
- case 6: chMode = MODE_1_2_2_1; break;
- default: chMode = MODE_INVALID;
- }
- return chMode;
-}
-
-//static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) {
-// if (profile == OMX_AUDIO_AACObjectLC) {
-// return AOT_AAC_LC;
-// } else if (profile == OMX_AUDIO_AACObjectHE) {
-// return AOT_SBR;
-// } else if (profile == OMX_AUDIO_AACObjectHE_PS) {
-// return AOT_PS;
-// } else if (profile == OMX_AUDIO_AACObjectLD) {
-// return AOT_ER_AAC_LD;
-// } else if (profile == OMX_AUDIO_AACObjectELD) {
-// return AOT_ER_AAC_ELD;
-// } else {
-// ALOGW("Unsupported AAC profile - defaulting to AAC-LC");
-// return AOT_AAC_LC;
-// }
-//}
-
-status_t C2SoftAacEnc::setAudioParams() {
- // We call this whenever sample rate, number of channels, bitrate or SBR mode change
- // in reponse to setParameter calls.
-
- ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio",
- mSampleRate, mNumChannels, mBitRate, mSBRMode, mSBRRatio);
-
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, mAACProfile)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
-
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mSampleRate)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mBitRate)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE,
- getChannelMode(mNumChannels))) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
-
- if (mSBRMode != -1 && mAACProfile == AOT_ER_AAC_ELD) {
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
- }
-
- /* SBR ratio parameter configurations:
- 0: Default configuration wherein SBR ratio is configured depending on audio object type by
- the FDK.
- 1: Downsampled SBR (default for ELD)
- 2: Dualrate SBR (default for HE-AAC)
- */
- if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) {
- ALOGE("Failed to set AAC encoder parameters");
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-void C2SoftAacEnc::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
-
- if (mSignalledError) {
- return;
- }
- bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
-
- if (!mSentCodecSpecificData) {
- // The very first thing we want to output is the codec specific
- // data.
-
- if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
- ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- uint32_t actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE);
- if (mBitRate != actualBitRate) {
- ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate);
- }
-
- AACENC_InfoStruct encInfo;
- if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
- ALOGE("Failed to get AAC encoder info");
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- std::unique_ptr<C2StreamCsdInfo::output> csd =
- C2StreamCsdInfo::output::AllocUnique(encInfo.confSize, 0u);
- // TODO: check NO_MEMORY
- memcpy(csd->m.value, encInfo.confBuf, encInfo.confSize);
- ALOGV("put csd");
-#if defined(LOG_NDEBUG) && !LOG_NDEBUG
- hexdump(csd->m.value, csd->flexCount());
-#endif
- work->worklets.front()->output.configUpdate.push_back(std::move(csd));
-
- mOutBufferSize = encInfo.maxOutBufBytes;
- mNumBytesPerInputFrame = encInfo.frameLength * mNumChannels * sizeof(int16_t);
- mInputTimeUs = work->input.ordinal.timestamp;
-
- mSentCodecSpecificData = true;
- }
-
- C2ReadView view = work->input.buffers[0]->data().linearBlocks().front().map().get();
- uint64_t timestamp = mInputTimeUs.peeku();
-
- size_t numFrames = (view.capacity() + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
- / mNumBytesPerInputFrame;
- ALOGV("capacity = %u; mInputSize = %zu; numFrames = %zu", view.capacity(), mInputSize, numFrames);
-
- std::shared_ptr<C2LinearBlock> block;
- std::unique_ptr<C2WriteView> wView;
- uint8_t *outPtr = nullptr;
- size_t outAvailable = 0u;
-
- if (numFrames) {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- // TODO: error handling, proper usage, etc.
- c2_status_t err = pool->fetchLinearBlock(mOutBufferSize * numFrames, usage, &block);
- if (err != C2_OK) {
- ALOGE("err = %d", err);
- }
-
- wView.reset(new C2WriteView(block->map().get()));
- outPtr = wView->data();
- outAvailable = wView->size();
- }
-
- AACENC_InArgs inargs;
- AACENC_OutArgs outargs;
- memset(&inargs, 0, sizeof(inargs));
- memset(&outargs, 0, sizeof(outargs));
- inargs.numInSamples = view.capacity() / sizeof(int16_t);
-
- void* inBuffer[] = { (unsigned char *)view.data() };
- INT inBufferIds[] = { IN_AUDIO_DATA };
- INT inBufferSize[] = { (INT)view.capacity() };
- INT inBufferElSize[] = { sizeof(int16_t) };
-
- AACENC_BufDesc inBufDesc;
- inBufDesc.numBufs = sizeof(inBuffer) / sizeof(void*);
- inBufDesc.bufs = (void**)&inBuffer;
- inBufDesc.bufferIdentifiers = inBufferIds;
- inBufDesc.bufSizes = inBufferSize;
- inBufDesc.bufElSizes = inBufferElSize;
-
- void* outBuffer[] = { outPtr };
- INT outBufferIds[] = { OUT_BITSTREAM_DATA };
- INT outBufferSize[] = { 0 };
- INT outBufferElSize[] = { sizeof(UCHAR) };
-
- AACENC_BufDesc outBufDesc;
- outBufDesc.numBufs = sizeof(outBuffer) / sizeof(void*);
- outBufDesc.bufs = (void**)&outBuffer;
- outBufDesc.bufferIdentifiers = outBufferIds;
- outBufDesc.bufSizes = outBufferSize;
- outBufDesc.bufElSizes = outBufferElSize;
-
- // Encode the mInputFrame, which is treated as a modulo buffer
- AACENC_ERROR encoderErr = AACENC_OK;
- size_t nOutputBytes = 0;
-
- while (encoderErr == AACENC_OK && inargs.numInSamples > 0) {
- memset(&outargs, 0, sizeof(outargs));
-
- outBuffer[0] = outPtr;
- outBufferSize[0] = outAvailable - nOutputBytes;
-
- encoderErr = aacEncEncode(mAACEncoder,
- &inBufDesc,
- &outBufDesc,
- &inargs,
- &outargs);
-
- if (encoderErr == AACENC_OK) {
- if (outargs.numOutBytes > 0) {
- mInputSize = 0;
- int consumed = ((view.capacity() / sizeof(int16_t)) - inargs.numInSamples);
- mInputTimeUs = work->input.ordinal.timestamp
- + (consumed * 1000000ll / mNumChannels / mSampleRate);
- } else {
- mInputSize += outargs.numInSamples * sizeof(int16_t);
- mInputTimeUs += outargs.numInSamples * 1000000ll / mNumChannels / mSampleRate;
- }
- outPtr += outargs.numOutBytes;
- nOutputBytes += outargs.numOutBytes;
-
- if (outargs.numInSamples > 0) {
- inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
- inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
- inargs.numInSamples -= outargs.numInSamples;
- }
- }
- ALOGV("nOutputBytes = %zu; inargs.numInSamples = %d", nOutputBytes, inargs.numInSamples);
- }
-
- if (eos && inBufferSize[0] > 0) {
- memset(&outargs, 0, sizeof(outargs));
-
- outBuffer[0] = outPtr;
- outBufferSize[0] = outAvailable - nOutputBytes;
-
- // Flush
- inargs.numInSamples = -1;
-
- (void)aacEncEncode(mAACEncoder,
- &inBufDesc,
- &outBufDesc,
- &inargs,
- &outargs);
-
- nOutputBytes += outargs.numOutBytes;
- }
-
- work->worklets.front()->output.flags =
- (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->worklets.front()->output.ordinal.timestamp = timestamp;
- work->workletsProcessed = 1u;
- if (nOutputBytes) {
- work->worklets.front()->output.buffers.push_back(
- createLinearBuffer(block, 0, nOutputBytes));
- }
-
-#if 0
- ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
- nOutputBytes, mInputTimeUs.peekll(), outHeader->nFlags);
-
- hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
-#endif
-}
-
-c2_status_t C2SoftAacEnc::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- switch (drainMode) {
- case DRAIN_COMPONENT_NO_EOS: // fall-through
- case NO_DRAIN:
- // no-op
- return C2_OK;
- case DRAIN_CHAIN:
- return C2_OMITTED;
- case DRAIN_COMPONENT_WITH_EOS:
- break;
- default:
- return C2_BAD_VALUE;
- }
-
- (void)pool;
- mSentCodecSpecificData = false;
- mInputSize = 0u;
-
- // TODO: we don't have any pending work at this time to drain.
- return C2_OK;
-}
-
-class C2SoftAacEncFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftAacEnc(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftAacEncFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftAacEncFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h
deleted file mode 100644
index c9f440f..0000000
--- a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_AAC_ENC_H_
-
-#define C2_SOFT_AAC_ENC_H_
-
-#include <SimpleC2Component.h>
-#include <media/stagefright/foundation/ABase.h>
-
-#include "aacenc_lib.h"
-
-namespace android {
-
-class C2SoftAacEnc : public SimpleC2Component {
-public:
- C2SoftAacEnc(const char *name, c2_node_id_t id);
- virtual ~C2SoftAacEnc();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- HANDLE_AACENCODER mAACEncoder;
-
- uint32_t mNumChannels;
- uint32_t mSampleRate;
- uint32_t mBitRate;
- int32_t mSBRMode;
- int32_t mSBRRatio;
- AUDIO_OBJECT_TYPE mAACProfile;
- UINT mNumBytesPerInputFrame;
- UINT mOutBufferSize;
-
- bool mSentCodecSpecificData;
- size_t mInputSize;
- c2_cntr64_t mInputTimeUs;
-
- bool mSignalledError;
-
- status_t initEncoder();
-
- status_t setAudioParams();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftAacEnc);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_AAC_ENC_H_
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index e4a2607..880f161 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -41,7 +41,7 @@
],
include_dirs: ["frameworks/av/media/libstagefright/include"],
- local_include_dirs: ["src"],
+ export_include_dirs: ["src"],
cflags: [
"-DOSCL_UNUSED_ARG(x)=(void)(x)",
@@ -110,7 +110,6 @@
],
compile_multilib: "32",
}
-
//###############################################################################
cc_test {
name: "libstagefright_amrnbdec_test",
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 4001d46..19fd4a8 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -63,7 +63,7 @@
],
include_dirs: ["frameworks/av/media/libstagefright/include"],
- local_include_dirs: ["src"],
+ export_include_dirs: ["src"],
cflags: [
"-DOSCL_UNUSED_ARG(x)=(void)(x)",
@@ -122,50 +122,6 @@
//###############################################################################
-cc_library_shared {
- name: "libstagefright_soft_c2amrnbenc",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftAmrNbEnc.cpp"],
-
- local_include_dirs: ["src"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: [
- "libstagefright_amrnbenc",
- ],
-
- shared_libs: [
- "libutils",
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libstagefright_amrnb_common",
- ],
-}
-
-//###############################################################################
-
cc_test {
name: "libstagefright_amrnbenc_test",
gtest: false,
diff --git a/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.cpp b/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.cpp
deleted file mode 100644
index 406d1ca..0000000
--- a/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftAmrNbEnc"
-#include <utils/Log.h>
-
-#include "gsmamr_enc.h"
-
-#include "C2SoftAmrNbEnc.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.amrnb.encoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatAudio)
- .outputFormat(C2FormatCompressed)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_AMR_NB)
- .build();
-}
-
-C2SoftAmrNbEnc::C2SoftAmrNbEnc(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mEncState(nullptr),
- mSidState(nullptr) {
-}
-
-C2SoftAmrNbEnc::~C2SoftAmrNbEnc() {
- onRelease();
-}
-
-c2_status_t C2SoftAmrNbEnc::onInit() {
- bool dtx_enable = false;
-
- if (AMREncodeInit(&mEncState, &mSidState, dtx_enable) != 0)
- return C2_CORRUPTED;
- mMode = MR795;
- mIsFirst = true;
- mSignalledError = false;
- mSignalledOutputEos = false;
- mAnchorTimeStamp = 0;
- mProcessedSamples = 0;
- mFilledLen = 0;
-
- return C2_OK;
-}
-
-void C2SoftAmrNbEnc::onRelease() {
- if (mEncState) {
- AMREncodeExit(&mEncState, &mSidState);
- mEncState = mSidState = nullptr;
- }
-}
-
-c2_status_t C2SoftAmrNbEnc::onStop() {
- if (AMREncodeReset(mEncState, mSidState) != 0)
- return C2_CORRUPTED;
- mIsFirst = true;
- mSignalledError = false;
- mSignalledOutputEos = false;
- mAnchorTimeStamp = 0;
- mProcessedSamples = 0;
- mFilledLen = 0;
-
- return C2_OK;
-}
-
-void C2SoftAmrNbEnc::onReset() {
- (void) onStop();
-}
-
-c2_status_t C2SoftAmrNbEnc::onFlush_sm() {
- return onStop();
-}
-
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-void C2SoftAmrNbEnc::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
- inSize, (int)work->input.ordinal.timestamp.peeku(),
- (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
-
- size_t outCapacity = kNumBytesPerInputFrame;
- outCapacity += mFilledLen + inSize;
- std::shared_ptr<C2LinearBlock> outputBlock;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = outputBlock->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- uint64_t outTimeStamp = mProcessedSamples * 1000000ll / kSampleRate;
- const uint8_t *inPtr = rView.data() + inOffset;
- size_t inPos = 0;
- size_t outPos = 0;
- while (inPos < inSize) {
- int validSamples = mFilledLen / sizeof(int16_t);
- if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
- memcpy(mInputFrame + validSamples, inPtr + inPos,
- (kNumBytesPerInputFrame - mFilledLen));
- inPos += (kNumBytesPerInputFrame - mFilledLen);
- } else {
- memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
- mFilledLen += (inSize - inPos);
- inPos += (inSize - inPos);
- if (eos) {
- validSamples = mFilledLen / sizeof(int16_t);
- memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
- } else break;
- }
- Frame_Type_3GPP frameType;
- int numEncBytes = AMREncode(mEncState, mSidState, mMode, mInputFrame,
- wView.data() + outPos, &frameType,
- AMR_TX_WMF);
- if (numEncBytes < 0 || numEncBytes > ((int)outCapacity - (int)outPos)) {
- ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- // Convert header byte from WMF to IETF format.
- if (numEncBytes > 0)
- wView.data()[outPos] = ((wView.data()[outPos] << 3) | 4) & 0x7c;
- outPos += numEncBytes;
- mProcessedSamples += kNumSamplesPerFrame;
- mFilledLen = 0;
- }
- ALOGV("causal sample size %d", mFilledLen);
- if (mIsFirst) {
- mIsFirst = false;
- mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
- }
- fillEmptyWork(work);
- if (outPos != 0) {
- work->worklets.front()->output.buffers.push_back(
- createLinearBuffer(std::move(outputBlock), 0, outPos));
- work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
- }
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
- }
-}
-
-c2_status_t C2SoftAmrNbEnc::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- onFlush_sm();
- return C2_OK;
-}
-
-class C2SoftAmrNbEncFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftAmrNbEnc(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftAmrNbEncFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftAmrNbEncFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.h b/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.h
deleted file mode 100644
index 9ced921..0000000
--- a/media/libstagefright/codecs/amrnb/enc/C2SoftAmrNbEnc.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_AMRNB_ENC_H_
-#define C2_SOFT_AMRNB_ENC_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-class C2SoftAmrNbEnc : public SimpleC2Component {
-public:
- C2SoftAmrNbEnc(const char *name, c2_node_id_t id);
- virtual ~C2SoftAmrNbEnc();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- static const int32_t kNumSamplesPerFrame = L_FRAME;
- static const int32_t kNumBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
- static const int32_t kSampleRate = 8000;
-
- void *mEncState;
- void *mSidState;
- Mode mMode;
- bool mIsFirst;
- bool mSignalledError;
- bool mSignalledOutputEos;
- uint64_t mAnchorTimeStamp;
- uint64_t mProcessedSamples;
- int32_t mFilledLen;
- int16_t mInputFrame[kNumSamplesPerFrame];
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftAmrNbEnc);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_AMRNB_ENC_H_
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index 14a73d6..9fefd81 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -45,8 +45,11 @@
],
include_dirs: ["frameworks/av/media/libstagefright/include"],
- local_include_dirs: ["src"],
- export_include_dirs: ["include"],
+
+ export_include_dirs: [
+ "src",
+ "include",
+ ],
cflags: [
"-DOSCL_UNUSED_ARG(x)=(void)(x)",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index d789096..cf50a04 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -42,44 +42,3 @@
ldflags: ["-Wl,-Bsymbolic"],
compile_multilib: "32",
}
-
-cc_library_shared {
- name: "libstagefright_soft_c2avcdec",
-
- static_libs: [
- "libavcdec",
- ],
- srcs: ["C2SoftAvcDec.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- include_dirs: [
- "external/libavc/decoder",
- "external/libavc/common",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libmedia",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: false, // true,
- diag: {
- cfi: false, // true,
- },
- },
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
diff --git a/media/libstagefright/codecs/avcdec/C2AvcConfig.h b/media/libstagefright/codecs/avcdec/C2AvcConfig.h
deleted file mode 100644
index a7e0d95..0000000
--- a/media/libstagefright/codecs/avcdec/C2AvcConfig.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef C2AVCCONFIG_H_
-#define C2AVCCONFIG_H_
-
-#include <C2Config.h>
-
-namespace android {
-
-enum : uint32_t {
- kParamIndexAvcProfile = kParamIndexParamStart + 1,
- kParamIndexAvcLevel,
- kParamIndexBlockSize,
- kParamIndexAlignment,
- kParamIndexFramerate,
- kParamIndexBlocksPerSecond,
-};
-
-enum C2AvcProfileIdc : uint32_t {
- kAvcProfileUnknown = 0,
- kAvcProfileBaseline = 66,
- kAvcProfileMain = 77,
- kAvcProfileExtended = 88,
- kAvcProfileHigh = 100,
- kAvcProfileHigh10 = 110,
- kAvcProfileHigh422 = 122,
- kAvcProfileHigh444 = 144,
-};
-
-enum C2AvcLevelIdc : uint32_t {
- kAvcLevelUnknown = 0,
- kAvcLevel10 = 10,
- kAvcLevel1b = 9,
- kAvcLevel11 = 11,
- kAvcLevel12 = 12,
- kAvcLevel13 = 13,
- kAvcLevel20 = 20,
- kAvcLevel21 = 21,
- kAvcLevel22 = 22,
- kAvcLevel30 = 30,
- kAvcLevel31 = 31,
- kAvcLevel32 = 32,
- kAvcLevel40 = 40,
- kAvcLevel41 = 41,
- kAvcLevel42 = 42,
- kAvcLevel50 = 50,
- kAvcLevel51 = 51,
- kAvcLevel52 = 52,
-};
-
-// profile for AVC video decoder [IN]
-typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2AvcProfileIdc>, kParamIndexAvcProfile>
- C2AvcProfileInfo;
-
-// level for AVC video decoder [IN]
-typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2AvcLevelIdc>, kParamIndexAvcLevel>
- C2AvcLevelInfo;
-
-// block size [OUT]
-typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexBlockSize> C2BlockSizeInfo;
-
-// alignment [OUT]
-typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexAlignment> C2AlignmentInfo;
-
-// frame rate [OUT, hint]
-typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexFramerate> C2FrameRateInfo;
-
-// blocks-per-second [OUT, hint]
-typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexBlocksPerSecond> C2BlocksPerSecondInfo;
-
-} // namespace android
-
-#endif // C2AVCCONFIG_H_
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
deleted file mode 100644
index 1fc2c8c..0000000
--- a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Copyright 2017 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 "C2SoftAvcDec"
-#include <utils/Log.h>
-
-#include <cmath>
-#include <thread>
-#include <cinttypes>
-
-#include "ih264_typedefs.h"
-#include "iv.h"
-#include "ivd.h"
-#include "ih264d.h"
-#include "C2SoftAvcDec.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <utils/misc.h>
-
-#include "ih264d_defs.h"
-
-namespace android {
-
-struct iv_obj_t : public ::iv_obj_t {};
-struct ivd_video_decode_ip_t : public ::ivd_video_decode_ip_t {};
-struct ivd_video_decode_op_t : public ::ivd_video_decode_op_t {};
-
-#define PRINT_TIME ALOGV
-
-constexpr char kComponentName[] = "c2.google.avc.decoder";
-// #define codingType OMX_VIDEO_CodingAVC
-#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_AVC
-
-/** Function and structure definitions to keep code similar for each codec */
-#define ivdec_api_function ih264d_api_function
-#define ivdext_create_ip_t ih264d_create_ip_t
-#define ivdext_create_op_t ih264d_create_op_t
-#define ivdext_delete_ip_t ih264d_delete_ip_t
-#define ivdext_delete_op_t ih264d_delete_op_t
-#define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t
-#define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t
-
-#define IVDEXT_CMD_CTL_SET_NUM_CORES \
- (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
-namespace {
-
-std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatVideo)
- .inputMediaType(MEDIA_MIMETYPE_VIDEO_AVC)
- .outputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
- .build();
-}
-
-void CopyPlane(
- uint8_t *dst, const C2PlaneInfo &plane,
- const uint8_t *src, uint32_t width, uint32_t height) {
- for (uint32_t row = 0; row < height; ++row) {
- for (uint32_t col = 0; col < width; ++col) {
- *dst = *src;
- dst += plane.colInc;
- ++src;
- }
- dst -= plane.colInc * width;
- dst += plane.rowInc;
- }
-}
-
-void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-} // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-
-C2SoftAvcDec::C2SoftAvcDec(
- const char *name,
- c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mCodecCtx(NULL),
- mOutBuffer(NULL),
- mIvColorFormat(IV_YUV_420P),
- mChangingResolution(false),
- mSignalledError(false),
- mWidth(320),
- mHeight(240),
- mInputOffset(0) {
- ALOGV("in %s", __func__);
- GETTIME(&mTimeStart, NULL);
-
- // If input dump is enabled, then open create an empty file
- GENERATE_FILE_NAMES();
- CREATE_DUMP_FILE(mInFile);
-}
-
-C2SoftAvcDec::~C2SoftAvcDec() {
- ALOGV("in %s", __func__);
- CHECK_EQ(deInitDecoder(), (status_t)OK);
-}
-
-c2_status_t C2SoftAvcDec::onInit() {
- // TODO: initialize using intf
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcDec::onStop() {
- ALOGV("onStop");
- mSignalledError = false;
- resetDecoder();
- resetPlugin();
-
- return C2_OK;
-}
-
-void C2SoftAvcDec::onReset() {
- ALOGV("onReset");
- (void)onStop();
-}
-
-void C2SoftAvcDec::onRelease() {
- (void)deInitDecoder();
-}
-
-c2_status_t C2SoftAvcDec::onFlush_sm() {
- setFlushMode();
-
- while (true) {
- ivd_video_decode_ip_t s_dec_ip;
- ivd_video_decode_op_t s_dec_op;
- IV_API_CALL_STATUS_T status;
- // size_t sizeY, sizeUV;
-
- setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0, 0u);
-
- status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
- if (0 == s_dec_op.u4_output_present) {
- resetPlugin();
- break;
- }
- }
-
- if (mOutBuffer) {
- free(mOutBuffer);
- mOutBuffer = NULL;
- }
- return C2_OK;
-}
-
-static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
- (void) ctxt;
- return memalign(alignment, size);
-}
-
-static void ivd_aligned_free(void *ctxt, void *buf) {
- (void) ctxt;
- free(buf);
- return;
-}
-
-static size_t GetCPUCoreCount() {
- long cpuCoreCount = 1;
-#if defined(_SC_NPROCESSORS_ONLN)
- cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
- // _SC_NPROC_ONLN must be defined...
- cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
- CHECK(cpuCoreCount >= 1);
- ALOGV("Number of CPU cores: %ld", cpuCoreCount);
- return (size_t)cpuCoreCount;
-}
-
-void C2SoftAvcDec::logVersion() {
- ivd_ctl_getversioninfo_ip_t s_ctl_ip;
- ivd_ctl_getversioninfo_op_t s_ctl_op;
- UWORD8 au1_buf[512];
- IV_API_CALL_STATUS_T status;
-
- s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
- s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
- s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
- s_ctl_ip.pv_version_buffer = au1_buf;
- s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
-
- status =
- ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Error in getting version number: 0x%x",
- s_ctl_op.u4_error_code);
- } else {
- ALOGV("Ittiam decoder version number: %s",
- (char *)s_ctl_ip.pv_version_buffer);
- }
- return;
-}
-
-status_t C2SoftAvcDec::setParams(size_t stride) {
- ivd_ctl_set_config_ip_t s_ctl_ip;
- ivd_ctl_set_config_op_t s_ctl_op;
- IV_API_CALL_STATUS_T status;
- s_ctl_ip.u4_disp_wd = (UWORD32)stride;
- s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
-
- s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
- s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
- s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
- s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
- s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
-
- ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
- status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Error in setting the run-time parameters: 0x%x",
- s_ctl_op.u4_error_code);
-
- return UNKNOWN_ERROR;
- }
-
- if (mOutBuffer != NULL) {
- free(mOutBuffer);
- }
- uint32_t bufferSize = mWidth * mHeight * 3 / 2;
- mOutBuffer = (uint8_t *)memalign(128, bufferSize);
- if (NULL == mOutBuffer) {
- ALOGE("Could not allocate output buffer of size %u", bufferSize);
- return C2_NO_MEMORY;
- }
- return OK;
-}
-
-status_t C2SoftAvcDec::resetPlugin() {
- mInputOffset = 0;
-
- /* Initialize both start and end times */
- gettimeofday(&mTimeStart, NULL);
- gettimeofday(&mTimeEnd, NULL);
-
- return OK;
-}
-
-status_t C2SoftAvcDec::resetDecoder() {
- ivd_ctl_reset_ip_t s_ctl_ip;
- ivd_ctl_reset_op_t s_ctl_op;
- IV_API_CALL_STATUS_T status;
-
- s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
- s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
- s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
-
- status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
- if (IV_SUCCESS != status) {
- ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
- mSignalledError = false;
-
- /* Set number of cores/threads to be used by the codec */
- setNumCores();
-
- mStride = 0;
- return OK;
-}
-
-status_t C2SoftAvcDec::setNumCores() {
- ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
- ivdext_ctl_set_num_cores_op_t s_set_cores_op;
- IV_API_CALL_STATUS_T status;
- s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
- s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
- s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
- s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
- status = ivdec_api_function(
- mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
- if (IV_SUCCESS != status) {
- ALOGE("Error in setting number of cores: 0x%x",
- s_set_cores_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
- return OK;
-}
-
-status_t C2SoftAvcDec::setFlushMode() {
- ALOGV("setFlushMode");
- IV_API_CALL_STATUS_T status;
- ivd_ctl_flush_ip_t s_video_flush_ip;
- ivd_ctl_flush_op_t s_video_flush_op;
-
- s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
- s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
- s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
-
- /* Set the decoder in Flush mode, subsequent decode() calls will flush */
- status = ivdec_api_function(
- mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
- s_video_flush_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftAvcDec::initDecoder() {
- IV_API_CALL_STATUS_T status;
-
- mNumCores = GetCPUCoreCount();
- mCodecCtx = NULL;
-
- mStride = mWidth;
-
- /* Initialize the decoder */
- {
- ivdext_create_ip_t s_create_ip;
- ivdext_create_op_t s_create_op;
-
- void *dec_fxns = (void *)ivdec_api_function;
-
- s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
- s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
- s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
- s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
- s_create_ip.s_ivd_create_ip_t.e_output_format = (IV_COLOR_FORMAT_T)mIvColorFormat;
- s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
- s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
- s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
-
- status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
-
- mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
- mCodecCtx->pv_fxns = dec_fxns;
- mCodecCtx->u4_size = sizeof(iv_obj_t);
-
- if (status != IV_SUCCESS) {
- ALOGE("Error in create: 0x%x",
- s_create_op.s_ivd_create_op_t.u4_error_code);
- deInitDecoder();
- return UNKNOWN_ERROR;
- }
- }
-
- /* Reset the plugin state */
- resetPlugin();
-
- /* Set the run time (dynamic) parameters */
- setParams(mStride);
-
- /* Set number of cores/threads to be used by the codec */
- setNumCores();
-
- /* Get codec version */
- logVersion();
-
- mFlushNeeded = false;
- return OK;
-}
-
-status_t C2SoftAvcDec::deInitDecoder() {
- IV_API_CALL_STATUS_T status;
-
- if (mCodecCtx) {
- ivdext_delete_ip_t s_delete_ip;
- ivdext_delete_op_t s_delete_op;
-
- s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
- s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
-
- s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
-
- status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
- if (status != IV_SUCCESS) {
- ALOGE("Error in delete: 0x%x",
- s_delete_op.s_ivd_delete_op_t.u4_error_code);
- return UNKNOWN_ERROR;
- }
- mCodecCtx = NULL;
- }
-
- mChangingResolution = false;
-
- return OK;
-}
-
-bool C2SoftAvcDec::getVUIParams() {
- IV_API_CALL_STATUS_T status;
- ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
- ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
-
- s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_ctl_get_vui_params_ip.e_sub_cmd =
- (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;
-
- s_ctl_get_vui_params_ip.u4_size =
- sizeof(ih264d_ctl_get_vui_params_ip_t);
-
- s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t);
-
- status = ivdec_api_function(
- (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
- (void *)&s_ctl_get_vui_params_op);
-
- if (status != IV_SUCCESS) {
- ALOGW("Error in getting VUI params: 0x%x",
- s_ctl_get_vui_params_op.u4_error_code);
- return false;
- }
-
- int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
- int32_t transfer = s_ctl_get_vui_params_op.u1_tfr_chars;
- int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coeffs;
- bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
-
- ColorAspects colorAspects;
- ColorUtils::convertIsoColorAspectsToCodecAspects(
- primaries, transfer, coeffs, fullRange, colorAspects);
-
- // Update color aspects if necessary.
- if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
- mBitstreamColorAspects = colorAspects;
- status_t err = handleColorAspectsChange();
- CHECK(err == OK);
- }
- return true;
-}
-
-bool C2SoftAvcDec::setDecodeArgs(
- ivd_video_decode_ip_t *ps_dec_ip,
- ivd_video_decode_op_t *ps_dec_op,
- C2ReadView *inBuffer,
- C2GraphicView *outBuffer,
- uint32_t workIndex,
- size_t inOffset) {
- size_t width = mWidth;
- size_t height = mHeight;
- size_t sizeY = width * height;
- size_t sizeUV;
-
- ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
- ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
- ps_dec_op->u4_output_present = 0;
-
- ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
-
- /* When in flush and after EOS with zero byte input,
- * inBuffer is set to zero. Hence check for non-null */
- if (inBuffer) {
- ps_dec_ip->u4_ts = workIndex;
- ps_dec_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data()) + inOffset;
- ps_dec_ip->u4_num_Bytes = inBuffer->capacity() - inOffset;
- } else {
- ps_dec_ip->u4_ts = 0;
- ps_dec_ip->pv_stream_buffer = NULL;
- ps_dec_ip->u4_num_Bytes = 0;
- }
-
- sizeUV = sizeY / 4;
- ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
- ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
- ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
-
- if (outBuffer) {
- if (outBuffer->width() < width ||
- outBuffer->height() < height) {
- ALOGE("Output buffer too small: provided (%dx%d) required (%zux%zu)",
- outBuffer->width(), outBuffer->height(), width, height);
- return false;
- }
- ALOGV("width = %u, stride[0] = %u, stride[1] = %u, stride[2] = %u",
- outBuffer->width(),
- outBuffer->layout().planes[0].rowInc,
- outBuffer->layout().planes[1].rowInc,
- outBuffer->layout().planes[2].rowInc);
- const C2PlanarLayout &layout = outBuffer->layout();
- ps_dec_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[0];
- if (layout.planes[0].rowInc != (int32_t)mWidth || layout.planes[1].colInc != 1) {
- ps_dec_ip->s_out_buffer.pu1_bufs[0] = mOutBuffer;
- }
- ps_dec_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[1];
- if (layout.planes[1].rowInc != (int32_t)mWidth / 2 || layout.planes[1].colInc != 1) {
- ps_dec_ip->s_out_buffer.pu1_bufs[1] = mOutBuffer + sizeY;
- }
- ps_dec_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[2];
- if (layout.planes[2].rowInc != (int32_t)mWidth / 2 || layout.planes[2].colInc != 1) {
- ps_dec_ip->s_out_buffer.pu1_bufs[2] = mOutBuffer + sizeY + sizeUV;
- }
- } else {
- // mOutBuffer always has the right size.
- ps_dec_ip->s_out_buffer.pu1_bufs[0] = mOutBuffer;
- ps_dec_ip->s_out_buffer.pu1_bufs[1] = mOutBuffer + sizeY;
- ps_dec_ip->s_out_buffer.pu1_bufs[2] = mOutBuffer + sizeY + sizeUV;
- }
-
- ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
- return true;
-}
-
-c2_status_t C2SoftAvcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
- if (NULL == mCodecCtx) {
- if (OK != initDecoder()) {
- ALOGE("Failed to initialize decoder");
- // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
- mSignalledError = true;
- return C2_CORRUPTED;
- }
- }
- if (mWidth != mStride) {
- /* Set the run-time (dynamic) parameters */
- mStride = mWidth;
- setParams(mStride);
- }
-
- if (!mAllocatedBlock) {
- // TODO: error handling
- // TODO: format & usage
- uint32_t format = HAL_PIXEL_FORMAT_YV12;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- ALOGV("using allocator %u", pool->getAllocatorId());
-
- (void)pool->fetchGraphicBlock(
- mWidth, mHeight, format, usage, &mAllocatedBlock);
- ALOGV("provided (%dx%d) required (%dx%d)",
- mAllocatedBlock->width(), mAllocatedBlock->height(), mWidth, mHeight);
- }
- return C2_OK;
-}
-
-void C2SoftAvcDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
- std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(mAllocatedBlock);
- mAllocatedBlock.reset();
- auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("EOS");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
- fillWork(work);
- } else {
- finish(index, fillWork);
- }
-}
-
-void C2SoftAvcDec::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- bool eos = false;
-
- work->result = C2_OK;
- work->workletsProcessed = 0u;
-
- const C2ConstLinearBlock buffer =
- work->input.buffers[0]->data().linearBlocks().front();
- if (buffer.size() == 0) {
- ALOGV("empty input: %llu", work->input.ordinal.frameIndex.peekull());
- // TODO: result?
- fillEmptyWork(work);
- if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) {
- eos = true;
- }
- return;
- } else if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- ALOGV("input EOS: %llu", work->input.ordinal.frameIndex.peekull());
- eos = true;
- }
-
- C2ReadView input = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (input.error() != C2_OK) {
- work->result = input.error();
- fillEmptyWork(work);
- ALOGD("map error: %d", input.error());
- return;
- }
- ALOGV("buffer.size() = %u, input.capacity() = %u", buffer.size(), input.capacity());
- uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
- size_t inOffset = 0u;
-
- while (inOffset < input.capacity()) {
- if (mSignalledError) {
- break;
- }
- (void)ensureDecoderState(pool);
- ivd_video_decode_ip_t s_dec_ip;
- ivd_video_decode_op_t s_dec_op;
- WORD32 timeDelay, timeTaken;
- //size_t sizeY, sizeUV;
-
- {
- C2GraphicView output = mAllocatedBlock->map().get();
- if (output.error() != C2_OK) {
- ALOGE("mapped err = %d", output.error());
- work->result = output.error();
- fillEmptyWork(work);
- return;
- }
- if (!setDecodeArgs(&s_dec_ip, &s_dec_op, &input, &output, workIndex, inOffset)) {
- ALOGE("Decoder arg setup failed");
- // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- break;
- }
- ALOGV("Decoder arg setup succeeded");
- // If input dump is enabled, then write to file
- DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes, mInputOffset);
-
- GETTIME(&mTimeStart, NULL);
- /* Compute time elapsed between end of previous decode()
- * to start of current decode() */
- TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
-
- IV_API_CALL_STATUS_T status;
- status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
- ALOGV("status = %d, error_code = %d", status, (s_dec_op.u4_error_code & 0xFF));
- if (s_dec_op.u4_output_present) {
- const C2PlanarLayout &layout = output.layout();
- if (layout.planes[0].rowInc != (int32_t)mWidth || layout.planes[1].colInc != 1) {
- CopyPlane(output.data()[0], layout.planes[0], mOutBuffer, mWidth, mHeight);
- }
- if (layout.planes[1].rowInc != (int32_t)mWidth / 2 || layout.planes[1].colInc != 1) {
- CopyPlane(
- output.data()[1], layout.planes[1],
- mOutBuffer + (mWidth * mHeight), mWidth / 2, mHeight / 2);
- }
- if (layout.planes[2].rowInc != (int32_t)mWidth / 2 || layout.planes[2].colInc != 1) {
- CopyPlane(
- output.data()[2], layout.planes[2],
- mOutBuffer + (mWidth * mHeight * 5 / 4), mWidth / 2, mHeight / 2);
- }
- }
- }
-
- bool unsupportedResolution =
- (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
-
- /* Check for unsupported dimensions */
- if (unsupportedResolution) {
- ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
- // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
- mSignalledError = true;
- break;
- }
-
- bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF));
- if (allocationFailed) {
- ALOGE("Allocation failure in decoder");
- // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
- mSignalledError = true;
- break;
- }
-
- bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
-
- getVUIParams();
-
- GETTIME(&mTimeEnd, NULL);
- /* Compute time taken for decode() */
- TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
-
- PRINT_TIME("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
- s_dec_op.u4_num_bytes_consumed);
- ALOGV("bytes total=%u", input.capacity());
- if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
- mFlushNeeded = true;
- }
-
- if (1 != s_dec_op.u4_frame_decoded_flag) {
- /* If the input did not contain picture data, return work without
- * buffer */
- ALOGV("no picture data: %u", workIndex);
- fillEmptyWork(work);
- }
-
- if (resChanged) {
- ALOGV("res changed");
- if (mFlushNeeded) {
- drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
- }
- resetDecoder();
- resetPlugin();
- mStride = mWidth;
- setParams(mStride);
- continue;
- }
-
- if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
- uint32_t width = s_dec_op.u4_pic_wd;
- uint32_t height = s_dec_op.u4_pic_ht;
- ALOGV("width = %u height = %u", width, height);
- if (width != mWidth || height != mHeight) {
- mAllocatedBlock.reset();
- mWidth = width;
- mHeight = height;
- }
- // TODO: continue?
- }
-
- if (mUpdateColorAspects) {
- //notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
- // kDescribeColorAspectsIndex, NULL);
- ALOGV("update color aspect");
- mUpdateColorAspects = false;
- }
-
- if (s_dec_op.u4_output_present) {
- ALOGV("output_present: %d", s_dec_op.u4_ts);
- finishWork(s_dec_op.u4_ts, work);
- }
-
- inOffset += s_dec_op.u4_num_bytes_consumed;
- }
- if (inOffset >= input.capacity()) {
- /* If input EOS is seen, drain the decoder.
- * There can be a case where EOS is sent along with last picture data
- * In that case, only after decoding that input data, decoder has to be
- * put in flush. This case is handled here */
- if (eos) {
- drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
- }
- }
-}
-
-c2_status_t C2SoftAvcDec::drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work) {
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
- setFlushMode();
-
- while (true) {
- (void)ensureDecoderState(pool);
- C2GraphicView output = mAllocatedBlock->map().get();
- if (output.error() != OK) {
- ALOGE("mapped err = %d", output.error());
- }
-
- ivd_video_decode_ip_t s_dec_ip;
- ivd_video_decode_op_t s_dec_op;
-
- setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, &output, 0, 0u);
-
- (void)ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
-
- if (s_dec_op.u4_output_present) {
- ALOGV("output_present: %d", s_dec_op.u4_ts);
- finishWork(s_dec_op.u4_ts, work);
- } else {
- break;
- }
- }
-
- if (drainMode == DRAIN_COMPONENT_WITH_EOS
- && work && work->workletsProcessed == 0u) {
- fillEmptyWork(work);
- }
-
- return C2_OK;
-}
-
-bool C2SoftAvcDec::colorAspectsDiffer(
- const ColorAspects &a, const ColorAspects &b) {
- if (a.mRange != b.mRange
- || a.mPrimaries != b.mPrimaries
- || a.mTransfer != b.mTransfer
- || a.mMatrixCoeffs != b.mMatrixCoeffs) {
- return true;
- }
- return false;
-}
-
-c2_status_t C2SoftAvcDec::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- return drainInternal(drainMode, pool, nullptr);
-}
-
-void C2SoftAvcDec::updateFinalColorAspects(
- const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
- Mutex::Autolock autoLock(mColorAspectsLock);
- ColorAspects newAspects;
- newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
- preferredAspects.mRange : otherAspects.mRange;
- newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
- preferredAspects.mPrimaries : otherAspects.mPrimaries;
- newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
- preferredAspects.mTransfer : otherAspects.mTransfer;
- newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
- preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
-
- // Check to see if need update mFinalColorAspects.
- if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
- mFinalColorAspects = newAspects;
- mUpdateColorAspects = true;
- }
-}
-
-status_t C2SoftAvcDec::handleColorAspectsChange() {
-// int perference = getColorAspectPreference();
-// ALOGD("Color Aspects preference: %d ", perference);
-//
-// if (perference == kPreferBitstream) {
-// updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
-// } else if (perference == kPreferContainer) {
-// updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
-// } else {
-// return OMX_ErrorUnsupportedSetting;
-// }
- updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
- return C2_OK;
-}
-
-class C2SoftAvcDecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftAvcDec(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftAvcDecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftAvcDecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
deleted file mode 100644
index d324a0f..0000000
--- a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-#ifndef C2_SOFT_H264_DEC_H_
-
-#define C2_SOFT_H264_DEC_H_
-
-#include <condition_variable>
-#include <map>
-#include <memory>
-#include <mutex>
-#include <set>
-#include <unordered_map>
-
-#include <util/C2ParamUtils.h>
-
-#include <C2Component.h>
-#include <C2Param.h>
-#include <SimpleC2Component.h>
-
-#include "C2AvcConfig.h"
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/ColorUtils.h>
-
-#include <sys/time.h>
-
-namespace android {
-
-struct iv_obj_t;
-struct ivd_video_decode_ip_t;
-struct ivd_video_decode_op_t;
-
-/** Number of entries in the time-stamp array */
-#define MAX_PENDING_WORKS 64
-
-/** Maximum number of cores supported by the codec */
-#define CODEC_MAX_NUM_CORES 4
-
-#define CODEC_MAX_WIDTH 1920
-
-#define CODEC_MAX_HEIGHT 1088
-
-/** Input buffer size */
-#define INPUT_BUF_SIZE (1024 * 1024)
-
-#define MIN(a, b) ((a) < (b)) ? (a) : (b)
-
-/** Get time */
-#define GETTIME(a, b) gettimeofday(a, b);
-
-/** Compute difference between start and end */
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
-#if 0
-class C2SoftAvcDecIntf : public C2ComponentInterface {
-public:
- struct SupportedValuesWithFields {
- C2FieldSupportedValues supported;
- std::set<C2ParamField> restrictingFields;
-
- SupportedValuesWithFields(const C2FieldSupportedValues &supported) : supported(supported) {}
- };
-
- C2SoftAvcDecIntf(const char *name, c2_node_id_t id);
- virtual ~C2SoftAvcDecIntf() override;
-
- // From C2ComponentInterface
- virtual C2String getName() const override;
- virtual c2_node_id_t getId() const override;
- virtual c2_status_t query_vb(
- const std::vector<C2Param*> &stackParams,
- const std::vector<C2Param::Index> &heapParamIndices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
- virtual c2_status_t config_vb(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
- virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override;
- virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override;
- // TODO: move this into some common store class
- std::shared_ptr<C2ParamReflector> getParamReflector() const;
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override;
- virtual c2_status_t querySupportedValues_vb(
- std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const override;
-
-private:
- class ParamReflector;
-
- const C2String mName;
- const c2_node_id_t mId;
-
- C2ComponentDomainInfo mDomainInfo;
- // TODO: config desc
- std::unique_ptr<C2PortMimeConfig::input> mInputPortMime;
- C2PortStreamCountConfig::input mInputStreamCount;
- std::unique_ptr<C2PortMimeConfig::output> mOutputPortMime;
- C2PortStreamCountConfig::output mOutputStreamCount;
- // TODO: C2StreamMimeConfig mInputStreamMime;
- // TODO: C2StreamMimeConfig mOutputStreamMime;
- C2StreamFormatConfig::input mInputStreamFormat;
- std::unique_ptr<C2PortBlockPoolsTuning::output> mOutputBlockPools;
- C2StreamFormatConfig::output mOutputStreamFormat;
- C2VideoSizeStreamInfo::output mVideoSize;
- C2MaxVideoSizeHintPortSetting::input mMaxVideoSizeHint;
- C2AvcProfileInfo::input mProfile;
- C2AvcLevelInfo::input mLevel;
- C2BlockSizeInfo::output mBlockSize;
- C2AlignmentInfo::output mAlignment;
- C2FrameRateInfo::output mFrameRate;
- C2BlocksPerSecondInfo::output mBlocksPerSecond;
-
- std::shared_ptr<C2ParamReflector> mParamReflector;
-
- std::unordered_map<uint32_t, C2Param *> mParams;
- // C2ParamField is LessThanComparable
- std::map<C2ParamField, SupportedValuesWithFields> mSupportedValues;
- std::unordered_map<
- uint32_t, std::function<std::unique_ptr<C2SettingResult>(C2Param *)>> mFieldVerifiers;
- std::vector<std::shared_ptr<C2ParamDescriptor>> mParamDescs;
-
- void updateSupportedValues();
- friend class C2SoftAvcDec;
-};
-#endif
-
-class C2SoftAvcDec : public SimpleC2Component {
-public:
- C2SoftAvcDec(const char *name, c2_node_id_t id);
- virtual ~C2SoftAvcDec();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- Mutex mColorAspectsLock;
- // color aspects passed from the framework.
- ColorAspects mDefaultColorAspects;
- // color aspects parsed from the bitstream.
- ColorAspects mBitstreamColorAspects;
- // final color aspects after combining the above two aspects.
- ColorAspects mFinalColorAspects;
- bool mUpdateColorAspects;
-
- bool colorAspectsDiffer(const ColorAspects &a, const ColorAspects &b);
-
- // This functions takes two color aspects and updates the mFinalColorAspects
- // based on |preferredAspects|.
- void updateFinalColorAspects(
- const ColorAspects &otherAspects, const ColorAspects &preferredAspects);
-
- // This function will update the mFinalColorAspects based on codec preference.
- status_t handleColorAspectsChange();
-
- std::shared_ptr<C2GraphicBlock> mAllocatedBlock;
-
- iv_obj_t *mCodecCtx; // Codec context
-
- size_t mNumCores; // Number of cores to be uesd by the codec
-
- struct timeval mTimeStart; // Time at the start of decode()
- struct timeval mTimeEnd; // Time at the end of decode()
-
- // Internal buffer to be used to flush out the buffers from decoder
- uint8_t *mOutBuffer;
-
-#ifdef FILE_DUMP_ENABLE
- char mInFile[200];
-#endif /* FILE_DUMP_ENABLE */
-
- int mIvColorFormat; // Ittiam Color format
-
- bool mIsInFlush; // codec is flush mode
- bool mReceivedEOS; // EOS is receieved on input port
-
- // The input stream has changed to a different resolution, which is still supported by the
- // codec. So the codec is switching to decode the new resolution.
- bool mChangingResolution;
- bool mFlushNeeded;
- bool mSignalledError;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mStride;
- size_t mInputOffset;
-
- status_t initDecoder();
- status_t deInitDecoder();
- status_t setFlushMode();
- status_t setParams(size_t stride);
- void logVersion();
- status_t setNumCores();
- status_t resetDecoder();
- status_t resetPlugin();
-
- c2_status_t ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool);
- void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work);
- c2_status_t drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work);
-
- bool setDecodeArgs(
- ivd_video_decode_ip_t *ps_dec_ip,
- ivd_video_decode_op_t *ps_dec_op,
- C2ReadView *inBuffer,
- C2GraphicView *outBuffer,
- uint32_t timeStampIx,
- size_t inOffset);
-
- bool getVUIParams();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftAvcDec);
-};
-
-#ifdef FILE_DUMP_ENABLE
-
-#define INPUT_DUMP_PATH "/sdcard/media/avcd_input"
-#define INPUT_DUMP_EXT "h264"
-
-#define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
- INPUT_DUMP_EXT); \
-}
-
-#define CREATE_DUMP_FILE(m_filename) { \
- FILE *fp = fopen(m_filename, "wb"); \
- if (fp != NULL) { \
- fclose(fp); \
- } else { \
- ALOGD("Could not open file %s", m_filename); \
- } \
-}
-#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
-{ \
- FILE *fp = fopen(m_filename, "ab"); \
- if (fp != NULL && m_buf != NULL && m_offset == 0) { \
- int i; \
- i = fwrite(m_buf, 1, m_size, fp); \
- ALOGD("fwrite ret %d to write %d", i, m_size); \
- if (i != (int) m_size) { \
- ALOGD("Error in fwrite, returned %d", i); \
- perror("Error in write to file"); \
- } \
- } else if (fp == NULL) { \
- ALOGD("Could not write to file %s", m_filename);\
- } \
- if (fp) { \
- fclose(fp); \
- } \
-}
-#else /* FILE_DUMP_ENABLE */
-#define INPUT_DUMP_PATH
-#define INPUT_DUMP_EXT
-#define OUTPUT_DUMP_PATH
-#define OUTPUT_DUMP_EXT
-#define GENERATE_FILE_NAMES()
-#define CREATE_DUMP_FILE(m_filename)
-#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
-#endif /* FILE_DUMP_ENABLE */
-
-} // namespace android
-
-#endif // C2_SOFT_H264_DEC_H_
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 67a2fdc..cefe77c 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -1,48 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2avcenc",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- static_libs: [ "libavcenc" ],
- srcs: ["C2SoftAvcEnc.cpp"],
-
- include_dirs: [
- "external/libavc/encoder",
- "external/libavc/common",
- "frameworks/av/media/libstagefright/include",
- "frameworks/native/include/media/hardware",
- ],
-
- shared_libs: [
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libutils",
- "liblog",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-variable",
- ],
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-cc_library_shared {
name: "libstagefright_soft_avcenc",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
deleted file mode 100644
index d75e4c1..0000000
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
+++ /dev/null
@@ -1,1253 +0,0 @@
-/*
- * Copyright 2018 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 "C2SoftAvcEnc"
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include "ih264_typedefs.h"
-#include "ih264e.h"
-#include "ih264e_error.h"
-#include "iv2.h"
-#include "ive2.h"
-#include "C2SoftAvcEnc.h"
-
-namespace android {
-
-#define ive_api_function ih264e_api_function
-
-constexpr char kComponentName[] = "c2.google.avc.encoder";
-
-namespace {
-
-// From external/libavc/encoder/ih264e_bitstream.h
-constexpr uint32_t MIN_STREAM_SIZE = 0x800;
-
-static size_t GetCPUCoreCount() {
- long cpuCoreCount = 1;
-#if defined(_SC_NPROCESSORS_ONLN)
- cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
- // _SC_NPROC_ONLN must be defined...
- cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
- CHECK(cpuCoreCount >= 1);
- ALOGV("Number of CPU cores: %ld", cpuCoreCount);
- return (size_t)cpuCoreCount;
-}
-
-std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatVideo)
- .outputFormat(C2FormatCompressed)
- .inputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
- .outputMediaType(MEDIA_MIMETYPE_VIDEO_AVC)
- .build();
-}
-
-void ConvertRGBToPlanarYUV(
- uint8_t *dstY, size_t dstStride, size_t dstVStride,
- const C2GraphicView &src) {
- CHECK((src.width() & 1) == 0);
- CHECK((src.height() & 1) == 0);
-
- uint8_t *dstU = dstY + dstStride * dstVStride;
- uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
-
- const C2PlanarLayout &layout = src.layout();
- const uint8_t *pRed = src.data()[C2PlanarLayout::PLANE_R];
- const uint8_t *pGreen = src.data()[C2PlanarLayout::PLANE_G];
- const uint8_t *pBlue = src.data()[C2PlanarLayout::PLANE_B];
-
- for (size_t y = 0; y < src.height(); ++y) {
- for (size_t x = 0; x < src.width(); ++x) {
- unsigned red = *pRed;
- unsigned green = *pGreen;
- unsigned blue = *pBlue;
-
- // using ITU-R BT.601 conversion matrix
- unsigned luma =
- ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
-
- dstY[x] = luma;
-
- if ((x & 1) == 0 && (y & 1) == 0) {
- unsigned U =
- ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
-
- unsigned V =
- ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
-
- dstU[x >> 1] = U;
- dstV[x >> 1] = V;
- }
- pRed += layout.planes[C2PlanarLayout::PLANE_R].colInc;
- pGreen += layout.planes[C2PlanarLayout::PLANE_G].colInc;
- pBlue += layout.planes[C2PlanarLayout::PLANE_B].colInc;
- }
-
- if ((y & 1) == 0) {
- dstU += dstStride >> 1;
- dstV += dstStride >> 1;
- }
-
- pRed -= layout.planes[C2PlanarLayout::PLANE_R].colInc * src.width();
- pGreen -= layout.planes[C2PlanarLayout::PLANE_G].colInc * src.width();
- pBlue -= layout.planes[C2PlanarLayout::PLANE_B].colInc * src.width();
- pRed += layout.planes[C2PlanarLayout::PLANE_R].rowInc;
- pGreen += layout.planes[C2PlanarLayout::PLANE_G].rowInc;
- pBlue += layout.planes[C2PlanarLayout::PLANE_B].rowInc;
-
- dstY += dstStride;
- }
-}
-
-} // namespace
-
-C2SoftAvcEnc::C2SoftAvcEnc(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mUpdateFlag(0),
- mIvVideoColorFormat(IV_YUV_420P),
- mAVCEncProfile(IV_PROFILE_BASE),
- mAVCEncLevel(41),
- mStarted(false),
- mSawInputEOS(false),
- mSawOutputEOS(false),
- mSignalledError(false),
- mCodecCtx(NULL),
- mWidth(1080),
- mHeight(1920),
- mFramerate(60),
- mBitrate(20000),
- // TODO: output buffer size
- mOutBufferSize(524288) {
-
- // If dump is enabled, then open create an empty file
- GENERATE_FILE_NAMES();
- CREATE_DUMP_FILE(mInFile);
- CREATE_DUMP_FILE(mOutFile);
-
- initEncParams();
-}
-
-C2SoftAvcEnc::~C2SoftAvcEnc() {
- releaseEncoder();
-}
-
-c2_status_t C2SoftAvcEnc::onInit() {
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::onStop() {
- return C2_OK;
-}
-
-void C2SoftAvcEnc::onReset() {
- // TODO: use IVE_CMD_CTL_RESET?
- releaseEncoder();
- initEncParams();
-}
-
-void C2SoftAvcEnc::onRelease() {
- releaseEncoder();
-}
-
-c2_status_t C2SoftAvcEnc::onFlush_sm() {
- // TODO: use IVE_CMD_CTL_FLUSH?
- return C2_OK;
-}
-
-void C2SoftAvcEnc::initEncParams() {
- mCodecCtx = NULL;
- mMemRecords = NULL;
- mNumMemRecords = DEFAULT_MEM_REC_CNT;
- mHeaderGenerated = 0;
- mNumCores = GetCPUCoreCount();
- mArch = DEFAULT_ARCH;
- mSliceMode = DEFAULT_SLICE_MODE;
- mSliceParam = DEFAULT_SLICE_PARAM;
- mHalfPelEnable = DEFAULT_HPEL;
- mIInterval = DEFAULT_I_INTERVAL;
- mIDRInterval = DEFAULT_IDR_INTERVAL;
- mDisableDeblkLevel = DEFAULT_DISABLE_DEBLK_LEVEL;
- mEnableFastSad = DEFAULT_ENABLE_FAST_SAD;
- mEnableAltRef = DEFAULT_ENABLE_ALT_REF;
- mEncSpeed = DEFAULT_ENC_SPEED;
- mIntra4x4 = DEFAULT_INTRA4x4;
- mConstrainedIntraFlag = DEFAULT_CONSTRAINED_INTRA;
- mAIRMode = DEFAULT_AIR;
- mAIRRefreshPeriod = DEFAULT_AIR_REFRESH_PERIOD;
- mPSNREnable = DEFAULT_PSNR_ENABLE;
- mReconEnable = DEFAULT_RECON_ENABLE;
- mEntropyMode = DEFAULT_ENTROPY_MODE;
- mBframes = DEFAULT_B_FRAMES;
-
- gettimeofday(&mTimeStart, NULL);
- gettimeofday(&mTimeEnd, NULL);
-}
-
-c2_status_t C2SoftAvcEnc::setDimensions() {
- ive_ctl_set_dimensions_ip_t s_dimensions_ip;
- ive_ctl_set_dimensions_op_t s_dimensions_op;
- IV_STATUS_T status;
-
- s_dimensions_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_dimensions_ip.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS;
- s_dimensions_ip.u4_ht = mHeight;
- s_dimensions_ip.u4_wd = mWidth;
-
- s_dimensions_ip.u4_timestamp_high = -1;
- s_dimensions_ip.u4_timestamp_low = -1;
-
- s_dimensions_ip.u4_size = sizeof(ive_ctl_set_dimensions_ip_t);
- s_dimensions_op.u4_size = sizeof(ive_ctl_set_dimensions_op_t);
-
- status = ive_api_function(mCodecCtx, &s_dimensions_ip, &s_dimensions_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set frame dimensions = 0x%x\n",
- s_dimensions_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setNumCores() {
- IV_STATUS_T status;
- ive_ctl_set_num_cores_ip_t s_num_cores_ip;
- ive_ctl_set_num_cores_op_t s_num_cores_op;
- s_num_cores_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_num_cores_ip.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES;
- s_num_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_CORES);
- s_num_cores_ip.u4_timestamp_high = -1;
- s_num_cores_ip.u4_timestamp_low = -1;
- s_num_cores_ip.u4_size = sizeof(ive_ctl_set_num_cores_ip_t);
-
- s_num_cores_op.u4_size = sizeof(ive_ctl_set_num_cores_op_t);
-
- status = ive_api_function(
- mCodecCtx, (void *) &s_num_cores_ip, (void *) &s_num_cores_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set processor params = 0x%x\n",
- s_num_cores_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setFrameRate() {
- ive_ctl_set_frame_rate_ip_t s_frame_rate_ip;
- ive_ctl_set_frame_rate_op_t s_frame_rate_op;
- IV_STATUS_T status;
-
- s_frame_rate_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_frame_rate_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE;
-
- s_frame_rate_ip.u4_src_frame_rate = mFramerate;
- s_frame_rate_ip.u4_tgt_frame_rate = mFramerate;
-
- s_frame_rate_ip.u4_timestamp_high = -1;
- s_frame_rate_ip.u4_timestamp_low = -1;
-
- s_frame_rate_ip.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t);
- s_frame_rate_op.u4_size = sizeof(ive_ctl_set_frame_rate_op_t);
-
- status = ive_api_function(mCodecCtx, &s_frame_rate_ip, &s_frame_rate_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set frame rate = 0x%x\n",
- s_frame_rate_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setIpeParams() {
- ive_ctl_set_ipe_params_ip_t s_ipe_params_ip;
- ive_ctl_set_ipe_params_op_t s_ipe_params_op;
- IV_STATUS_T status;
-
- s_ipe_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_ipe_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS;
-
- s_ipe_params_ip.u4_enable_intra_4x4 = mIntra4x4;
- s_ipe_params_ip.u4_enc_speed_preset = mEncSpeed;
- s_ipe_params_ip.u4_constrained_intra_pred = mConstrainedIntraFlag;
-
- s_ipe_params_ip.u4_timestamp_high = -1;
- s_ipe_params_ip.u4_timestamp_low = -1;
-
- s_ipe_params_ip.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t);
- s_ipe_params_op.u4_size = sizeof(ive_ctl_set_ipe_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_ipe_params_ip, &s_ipe_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set ipe params = 0x%x\n",
- s_ipe_params_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setBitRate() {
- ive_ctl_set_bitrate_ip_t s_bitrate_ip;
- ive_ctl_set_bitrate_op_t s_bitrate_op;
- IV_STATUS_T status;
-
- s_bitrate_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_bitrate_ip.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE;
-
- s_bitrate_ip.u4_target_bitrate = mBitrate;
-
- s_bitrate_ip.u4_timestamp_high = -1;
- s_bitrate_ip.u4_timestamp_low = -1;
-
- s_bitrate_ip.u4_size = sizeof(ive_ctl_set_bitrate_ip_t);
- s_bitrate_op.u4_size = sizeof(ive_ctl_set_bitrate_op_t);
-
- status = ive_api_function(mCodecCtx, &s_bitrate_ip, &s_bitrate_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set bit rate = 0x%x\n", s_bitrate_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type) {
- ive_ctl_set_frame_type_ip_t s_frame_type_ip;
- ive_ctl_set_frame_type_op_t s_frame_type_op;
- IV_STATUS_T status;
- s_frame_type_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_frame_type_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE;
-
- s_frame_type_ip.e_frame_type = e_frame_type;
-
- s_frame_type_ip.u4_timestamp_high = -1;
- s_frame_type_ip.u4_timestamp_low = -1;
-
- s_frame_type_ip.u4_size = sizeof(ive_ctl_set_frame_type_ip_t);
- s_frame_type_op.u4_size = sizeof(ive_ctl_set_frame_type_op_t);
-
- status = ive_api_function(mCodecCtx, &s_frame_type_ip, &s_frame_type_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set frame type = 0x%x\n",
- s_frame_type_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setQp() {
- ive_ctl_set_qp_ip_t s_qp_ip;
- ive_ctl_set_qp_op_t s_qp_op;
- IV_STATUS_T status;
-
- s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP;
-
- s_qp_ip.u4_i_qp = DEFAULT_I_QP;
- s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX;
- s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN;
-
- s_qp_ip.u4_p_qp = DEFAULT_P_QP;
- s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX;
- s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN;
-
- s_qp_ip.u4_b_qp = DEFAULT_P_QP;
- s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX;
- s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN;
-
- s_qp_ip.u4_timestamp_high = -1;
- s_qp_ip.u4_timestamp_low = -1;
-
- s_qp_ip.u4_size = sizeof(ive_ctl_set_qp_ip_t);
- s_qp_op.u4_size = sizeof(ive_ctl_set_qp_op_t);
-
- status = ive_api_function(mCodecCtx, &s_qp_ip, &s_qp_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set qp 0x%x\n", s_qp_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setEncMode(IVE_ENC_MODE_T e_enc_mode) {
- IV_STATUS_T status;
- ive_ctl_set_enc_mode_ip_t s_enc_mode_ip;
- ive_ctl_set_enc_mode_op_t s_enc_mode_op;
-
- s_enc_mode_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_enc_mode_ip.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE;
-
- s_enc_mode_ip.e_enc_mode = e_enc_mode;
-
- s_enc_mode_ip.u4_timestamp_high = -1;
- s_enc_mode_ip.u4_timestamp_low = -1;
-
- s_enc_mode_ip.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t);
- s_enc_mode_op.u4_size = sizeof(ive_ctl_set_enc_mode_op_t);
-
- status = ive_api_function(mCodecCtx, &s_enc_mode_ip, &s_enc_mode_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set in header encode mode = 0x%x\n",
- s_enc_mode_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setVbvParams() {
- ive_ctl_set_vbv_params_ip_t s_vbv_ip;
- ive_ctl_set_vbv_params_op_t s_vbv_op;
- IV_STATUS_T status;
-
- s_vbv_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_vbv_ip.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS;
-
- s_vbv_ip.u4_vbv_buf_size = 0;
- s_vbv_ip.u4_vbv_buffer_delay = 1000;
-
- s_vbv_ip.u4_timestamp_high = -1;
- s_vbv_ip.u4_timestamp_low = -1;
-
- s_vbv_ip.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t);
- s_vbv_op.u4_size = sizeof(ive_ctl_set_vbv_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_vbv_ip, &s_vbv_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set VBV params = 0x%x\n", s_vbv_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setAirParams() {
- ive_ctl_set_air_params_ip_t s_air_ip;
- ive_ctl_set_air_params_op_t s_air_op;
- IV_STATUS_T status;
-
- s_air_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_air_ip.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS;
-
- s_air_ip.e_air_mode = mAIRMode;
- s_air_ip.u4_air_refresh_period = mAIRRefreshPeriod;
-
- s_air_ip.u4_timestamp_high = -1;
- s_air_ip.u4_timestamp_low = -1;
-
- s_air_ip.u4_size = sizeof(ive_ctl_set_air_params_ip_t);
- s_air_op.u4_size = sizeof(ive_ctl_set_air_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_air_ip, &s_air_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set air params = 0x%x\n", s_air_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setMeParams() {
- IV_STATUS_T status;
- ive_ctl_set_me_params_ip_t s_me_params_ip;
- ive_ctl_set_me_params_op_t s_me_params_op;
-
- s_me_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_me_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS;
-
- s_me_params_ip.u4_enable_fast_sad = mEnableFastSad;
- s_me_params_ip.u4_enable_alt_ref = mEnableAltRef;
-
- s_me_params_ip.u4_enable_hpel = mHalfPelEnable;
- s_me_params_ip.u4_enable_qpel = DEFAULT_QPEL;
- s_me_params_ip.u4_me_speed_preset = DEFAULT_ME_SPEED;
- s_me_params_ip.u4_srch_rng_x = DEFAULT_SRCH_RNG_X;
- s_me_params_ip.u4_srch_rng_y = DEFAULT_SRCH_RNG_Y;
-
- s_me_params_ip.u4_timestamp_high = -1;
- s_me_params_ip.u4_timestamp_low = -1;
-
- s_me_params_ip.u4_size = sizeof(ive_ctl_set_me_params_ip_t);
- s_me_params_op.u4_size = sizeof(ive_ctl_set_me_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_me_params_ip, &s_me_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set me params = 0x%x\n", s_me_params_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setGopParams() {
- IV_STATUS_T status;
- ive_ctl_set_gop_params_ip_t s_gop_params_ip;
- ive_ctl_set_gop_params_op_t s_gop_params_op;
-
- s_gop_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_gop_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS;
-
- s_gop_params_ip.u4_i_frm_interval = mIInterval;
- s_gop_params_ip.u4_idr_frm_interval = mIDRInterval;
-
- s_gop_params_ip.u4_timestamp_high = -1;
- s_gop_params_ip.u4_timestamp_low = -1;
-
- s_gop_params_ip.u4_size = sizeof(ive_ctl_set_gop_params_ip_t);
- s_gop_params_op.u4_size = sizeof(ive_ctl_set_gop_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_gop_params_ip, &s_gop_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set GOP params = 0x%x\n",
- s_gop_params_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setProfileParams() {
- IV_STATUS_T status;
- ive_ctl_set_profile_params_ip_t s_profile_params_ip;
- ive_ctl_set_profile_params_op_t s_profile_params_op;
-
- s_profile_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_profile_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS;
-
- s_profile_params_ip.e_profile = DEFAULT_EPROFILE;
- s_profile_params_ip.u4_entropy_coding_mode = mEntropyMode;
- s_profile_params_ip.u4_timestamp_high = -1;
- s_profile_params_ip.u4_timestamp_low = -1;
-
- s_profile_params_ip.u4_size = sizeof(ive_ctl_set_profile_params_ip_t);
- s_profile_params_op.u4_size = sizeof(ive_ctl_set_profile_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_profile_params_ip, &s_profile_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to set profile params = 0x%x\n",
- s_profile_params_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setDeblockParams() {
- IV_STATUS_T status;
- ive_ctl_set_deblock_params_ip_t s_deblock_params_ip;
- ive_ctl_set_deblock_params_op_t s_deblock_params_op;
-
- s_deblock_params_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_deblock_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS;
-
- s_deblock_params_ip.u4_disable_deblock_level = mDisableDeblkLevel;
-
- s_deblock_params_ip.u4_timestamp_high = -1;
- s_deblock_params_ip.u4_timestamp_low = -1;
-
- s_deblock_params_ip.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t);
- s_deblock_params_op.u4_size = sizeof(ive_ctl_set_deblock_params_op_t);
-
- status = ive_api_function(mCodecCtx, &s_deblock_params_ip, &s_deblock_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("Unable to enable/disable deblock params = 0x%x\n",
- s_deblock_params_op.u4_error_code);
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-void C2SoftAvcEnc::logVersion() {
- ive_ctl_getversioninfo_ip_t s_ctl_ip;
- ive_ctl_getversioninfo_op_t s_ctl_op;
- UWORD8 au1_buf[512];
- IV_STATUS_T status;
-
- s_ctl_ip.e_cmd = IVE_CMD_VIDEO_CTL;
- s_ctl_ip.e_sub_cmd = IVE_CMD_CTL_GETVERSION;
- s_ctl_ip.u4_size = sizeof(ive_ctl_getversioninfo_ip_t);
- s_ctl_op.u4_size = sizeof(ive_ctl_getversioninfo_op_t);
- s_ctl_ip.pu1_version = au1_buf;
- s_ctl_ip.u4_version_bufsize = sizeof(au1_buf);
-
- status = ive_api_function(mCodecCtx, (void *) &s_ctl_ip, (void *) &s_ctl_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Error in getting version: 0x%x", s_ctl_op.u4_error_code);
- } else {
- ALOGV("Ittiam encoder version: %s", (char *)s_ctl_ip.pu1_version);
- }
- return;
-}
-
-c2_status_t C2SoftAvcEnc::initEncoder() {
- IV_STATUS_T status;
- WORD32 level;
- uint32_t displaySizeY;
-
- CHECK(!mStarted);
-
- c2_status_t errType = C2_OK;
-
- displaySizeY = mWidth * mHeight;
- if (displaySizeY > (1920 * 1088)) {
- level = 50;
- } else if (displaySizeY > (1280 * 720)) {
- level = 40;
- } else if (displaySizeY > (720 * 576)) {
- level = 31;
- } else if (displaySizeY > (624 * 320)) {
- level = 30;
- } else if (displaySizeY > (352 * 288)) {
- level = 21;
- } else if (displaySizeY > (176 * 144)) {
- level = 20;
- } else {
- level = 10;
- }
- mAVCEncLevel = MAX(level, mAVCEncLevel);
-
- mStride = mWidth;
-
- // TODO
- mIvVideoColorFormat = IV_YUV_420P;
-
- ALOGD("Params width %d height %d level %d colorFormat %d", mWidth,
- mHeight, mAVCEncLevel, mIvVideoColorFormat);
-
- /* Getting Number of MemRecords */
- {
- iv_num_mem_rec_ip_t s_num_mem_rec_ip;
- iv_num_mem_rec_op_t s_num_mem_rec_op;
-
- s_num_mem_rec_ip.u4_size = sizeof(iv_num_mem_rec_ip_t);
- s_num_mem_rec_op.u4_size = sizeof(iv_num_mem_rec_op_t);
-
- s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
-
- status = ive_api_function(0, &s_num_mem_rec_ip, &s_num_mem_rec_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Get number of memory records failed = 0x%x\n",
- s_num_mem_rec_op.u4_error_code);
- return C2_CORRUPTED;
- }
-
- mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
- }
-
- /* Allocate array to hold memory records */
- if (mNumMemRecords > SIZE_MAX / sizeof(iv_mem_rec_t)) {
- ALOGE("requested memory size is too big.");
- return C2_CORRUPTED;
- }
- mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t));
- if (NULL == mMemRecords) {
- ALOGE("Unable to allocate memory for hold memory records: Size %zu",
- mNumMemRecords * sizeof(iv_mem_rec_t));
- mSignalledError = true;
- return C2_CORRUPTED;
- }
-
- {
- iv_mem_rec_t *ps_mem_rec;
- ps_mem_rec = mMemRecords;
- for (size_t i = 0; i < mNumMemRecords; i++) {
- ps_mem_rec->u4_size = sizeof(iv_mem_rec_t);
- ps_mem_rec->pv_base = NULL;
- ps_mem_rec->u4_mem_size = 0;
- ps_mem_rec->u4_mem_alignment = 0;
- ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE;
-
- ps_mem_rec++;
- }
- }
-
- /* Getting MemRecords Attributes */
- {
- iv_fill_mem_rec_ip_t s_fill_mem_rec_ip;
- iv_fill_mem_rec_op_t s_fill_mem_rec_op;
-
- s_fill_mem_rec_ip.u4_size = sizeof(iv_fill_mem_rec_ip_t);
- s_fill_mem_rec_op.u4_size = sizeof(iv_fill_mem_rec_op_t);
-
- s_fill_mem_rec_ip.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
- s_fill_mem_rec_ip.ps_mem_rec = mMemRecords;
- s_fill_mem_rec_ip.u4_num_mem_rec = mNumMemRecords;
- s_fill_mem_rec_ip.u4_max_wd = mWidth;
- s_fill_mem_rec_ip.u4_max_ht = mHeight;
- s_fill_mem_rec_ip.u4_max_level = mAVCEncLevel;
- s_fill_mem_rec_ip.e_color_format = DEFAULT_INP_COLOR_FORMAT;
- s_fill_mem_rec_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM;
- s_fill_mem_rec_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM;
- s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X;
- s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y;
-
- status = ive_api_function(0, &s_fill_mem_rec_ip, &s_fill_mem_rec_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Fill memory records failed = 0x%x\n",
- s_fill_mem_rec_op.u4_error_code);
- return C2_CORRUPTED;
- }
- }
-
- /* Allocating Memory for Mem Records */
- {
- WORD32 total_size;
- iv_mem_rec_t *ps_mem_rec;
- total_size = 0;
- ps_mem_rec = mMemRecords;
-
- for (size_t i = 0; i < mNumMemRecords; i++) {
- ps_mem_rec->pv_base = ive_aligned_malloc(
- ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
- if (ps_mem_rec->pv_base == NULL) {
- ALOGE("Allocation failure for mem record id %zu size %u\n", i,
- ps_mem_rec->u4_mem_size);
- return C2_CORRUPTED;
-
- }
- total_size += ps_mem_rec->u4_mem_size;
-
- ps_mem_rec++;
- }
- }
-
- /* Codec Instance Creation */
- {
- ive_init_ip_t s_init_ip;
- ive_init_op_t s_init_op;
-
- mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
- mCodecCtx->u4_size = sizeof(iv_obj_t);
- mCodecCtx->pv_fxns = (void *)ive_api_function;
-
- s_init_ip.u4_size = sizeof(ive_init_ip_t);
- s_init_op.u4_size = sizeof(ive_init_op_t);
-
- s_init_ip.e_cmd = IV_CMD_INIT;
- s_init_ip.u4_num_mem_rec = mNumMemRecords;
- s_init_ip.ps_mem_rec = mMemRecords;
- s_init_ip.u4_max_wd = mWidth;
- s_init_ip.u4_max_ht = mHeight;
- s_init_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM;
- s_init_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM;
- s_init_ip.u4_max_level = mAVCEncLevel;
- s_init_ip.e_inp_color_fmt = mIvVideoColorFormat;
-
- if (mReconEnable || mPSNREnable) {
- s_init_ip.u4_enable_recon = 1;
- } else {
- s_init_ip.u4_enable_recon = 0;
- }
- s_init_ip.e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT;
- s_init_ip.e_rc_mode = DEFAULT_RC_MODE;
- s_init_ip.u4_max_framerate = DEFAULT_MAX_FRAMERATE;
- s_init_ip.u4_max_bitrate = DEFAULT_MAX_BITRATE;
- s_init_ip.u4_num_bframes = mBframes;
- s_init_ip.e_content_type = IV_PROGRESSIVE;
- s_init_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X;
- s_init_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y;
- s_init_ip.e_slice_mode = mSliceMode;
- s_init_ip.u4_slice_param = mSliceParam;
- s_init_ip.e_arch = mArch;
- s_init_ip.e_soc = DEFAULT_SOC;
-
- status = ive_api_function(mCodecCtx, &s_init_ip, &s_init_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Init encoder failed = 0x%x\n", s_init_op.u4_error_code);
- return C2_CORRUPTED;
- }
- }
-
- /* Get Codec Version */
- logVersion();
-
- /* set processor details */
- setNumCores();
-
- /* Video control Set Frame dimensions */
- setDimensions();
-
- /* Video control Set Frame rates */
- setFrameRate();
-
- /* Video control Set IPE Params */
- setIpeParams();
-
- /* Video control Set Bitrate */
- setBitRate();
-
- /* Video control Set QP */
- setQp();
-
- /* Video control Set AIR params */
- setAirParams();
-
- /* Video control Set VBV params */
- setVbvParams();
-
- /* Video control Set Motion estimation params */
- setMeParams();
-
- /* Video control Set GOP params */
- setGopParams();
-
- /* Video control Set Deblock params */
- setDeblockParams();
-
- /* Video control Set Profile params */
- setProfileParams();
-
- /* Video control Set in Encode header mode */
- setEncMode(IVE_ENC_MODE_HEADER);
-
- ALOGV("init_codec successfull");
-
- mSpsPpsHeaderReceived = false;
- mStarted = true;
-
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::releaseEncoder() {
- IV_STATUS_T status = IV_SUCCESS;
- iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip;
- iv_retrieve_mem_rec_op_t s_retrieve_mem_op;
- iv_mem_rec_t *ps_mem_rec;
-
- if (!mStarted) {
- return C2_OK;
- }
-
- s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
- s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
- s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
- s_retrieve_mem_ip.ps_mem_rec = mMemRecords;
-
- status = ive_api_function(mCodecCtx, &s_retrieve_mem_ip, &s_retrieve_mem_op);
-
- if (status != IV_SUCCESS) {
- ALOGE("Unable to retrieve memory records = 0x%x\n",
- s_retrieve_mem_op.u4_error_code);
- return C2_CORRUPTED;
- }
-
- /* Free memory records */
- ps_mem_rec = mMemRecords;
- for (size_t i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) {
- ive_aligned_free(ps_mem_rec->pv_base);
- ps_mem_rec++;
- }
-
- free(mMemRecords);
-
- // clear other pointers into the space being free()d
- mCodecCtx = NULL;
-
- mStarted = false;
-
- return C2_OK;
-}
-
-c2_status_t C2SoftAvcEnc::setEncodeArgs(
- ive_video_encode_ip_t *ps_encode_ip,
- ive_video_encode_op_t *ps_encode_op,
- const C2GraphicView *const input,
- uint8_t *base,
- uint32_t capacity,
- uint64_t timestamp) {
- iv_raw_buf_t *ps_inp_raw_buf;
-
- ps_inp_raw_buf = &ps_encode_ip->s_inp_buf;
- ps_encode_ip->s_out_buf.pv_buf = base;
- ps_encode_ip->s_out_buf.u4_bytes = 0;
- ps_encode_ip->s_out_buf.u4_bufsize = capacity;
- ps_encode_ip->u4_size = sizeof(ive_video_encode_ip_t);
- ps_encode_op->u4_size = sizeof(ive_video_encode_op_t);
-
- ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE;
- ps_encode_ip->pv_bufs = NULL;
- ps_encode_ip->pv_mb_info = NULL;
- ps_encode_ip->pv_pic_info = NULL;
- ps_encode_ip->u4_mb_info_type = 0;
- ps_encode_ip->u4_pic_info_type = 0;
- ps_encode_ip->u4_is_last = 0;
- ps_encode_ip->u4_timestamp_high = timestamp >> 32;
- ps_encode_ip->u4_timestamp_low = timestamp & 0xFFFFFFFF;
- ps_encode_op->s_out_buf.pv_buf = NULL;
-
- /* Initialize color formats */
- memset(ps_inp_raw_buf, 0, sizeof(iv_raw_buf_t));
- ps_inp_raw_buf->u4_size = sizeof(iv_raw_buf_t);
- ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat;
- if (input == nullptr) {
- if (mSawInputEOS){
- ps_encode_ip->u4_is_last = 1;
- }
- return C2_OK;
- }
-
- ALOGV("width = %d, height = %d", input->width(), input->height());
- if (mWidth != input->width() || mHeight != input->height()) {
- return C2_BAD_VALUE;
- }
- const C2PlanarLayout &layout = input->layout();
- uint8_t *yPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
- uint8_t *uPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
- uint8_t *vPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_V]);
- int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
- int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
-
- switch (layout.type) {
- case C2PlanarLayout::TYPE_RGB:
- // fall-through
- case C2PlanarLayout::TYPE_RGBA: {
- size_t yPlaneSize = input->width() * input->height();
- std::unique_ptr<uint8_t[]> freeBuffer;
- if (mFreeConversionBuffers.empty()) {
- freeBuffer.reset(new uint8_t[yPlaneSize * 3 / 2]);
- } else {
- freeBuffer.swap(mFreeConversionBuffers.front());
- mFreeConversionBuffers.pop_front();
- }
- yPlane = freeBuffer.get();
- mConversionBuffersInUse.push_back(std::move(freeBuffer));
- uPlane = yPlane + yPlaneSize;
- vPlane = uPlane + yPlaneSize / 4;
- yStride = input->width();
- uStride = vStride = input->width() / 2;
- ConvertRGBToPlanarYUV(yPlane, yStride, input->height(), *input);
- break;
- }
- case C2PlanarLayout::TYPE_YUV:
- // fall-through
- case C2PlanarLayout::TYPE_YUVA:
- // Do nothing
- break;
- default:
- ALOGE("Unrecognized plane type: %d", layout.type);
- return C2_BAD_VALUE;
- }
-
- switch (mIvVideoColorFormat) {
- case IV_YUV_420P:
- {
- // input buffer is supposed to be const but Ittiam API wants bare pointer.
- ps_inp_raw_buf->apv_bufs[0] = yPlane;
- ps_inp_raw_buf->apv_bufs[1] = uPlane;
- ps_inp_raw_buf->apv_bufs[2] = vPlane;
-
- ps_inp_raw_buf->au4_wd[0] = input->width();
- ps_inp_raw_buf->au4_wd[1] = input->width() / 2;
- ps_inp_raw_buf->au4_wd[2] = input->width() / 2;
-
- ps_inp_raw_buf->au4_ht[0] = input->height();
- ps_inp_raw_buf->au4_ht[1] = input->height() / 2;
- ps_inp_raw_buf->au4_ht[2] = input->height() / 2;
-
- ps_inp_raw_buf->au4_strd[0] = yStride;
- ps_inp_raw_buf->au4_strd[1] = uStride;
- ps_inp_raw_buf->au4_strd[2] = vStride;
- break;
- }
-
- case IV_YUV_422ILE:
- {
- // TODO
- // ps_inp_raw_buf->apv_bufs[0] = pu1_buf;
- // ps_inp_raw_buf->au4_wd[0] = mWidth * 2;
- // ps_inp_raw_buf->au4_ht[0] = mHeight;
- // ps_inp_raw_buf->au4_strd[0] = mStride * 2;
- break;
- }
-
- case IV_YUV_420SP_UV:
- case IV_YUV_420SP_VU:
- default:
- {
- ps_inp_raw_buf->apv_bufs[0] = yPlane;
- ps_inp_raw_buf->apv_bufs[1] = uPlane;
-
- ps_inp_raw_buf->au4_wd[0] = input->width();
- ps_inp_raw_buf->au4_wd[1] = input->width();
-
- ps_inp_raw_buf->au4_ht[0] = input->height();
- ps_inp_raw_buf->au4_ht[1] = input->height() / 2;
-
- ps_inp_raw_buf->au4_strd[0] = yStride;
- ps_inp_raw_buf->au4_strd[1] = uStride;
- break;
- }
- }
- return C2_OK;
-}
-
-void C2SoftAvcEnc::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
-
- IV_STATUS_T status;
- WORD32 timeDelay, timeTaken;
- uint64_t timestamp = work->input.ordinal.timestamp.peekull();
-
- // Initialize encoder if not already initialized
- if (mCodecCtx == NULL) {
- if (C2_OK != initEncoder()) {
- ALOGE("Failed to initialize encoder");
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return;
- }
- }
- if (mSignalledError) {
- return;
- }
-
- // while (!mSawOutputEOS && !outQueue.empty()) {
- c2_status_t error;
- ive_video_encode_ip_t s_encode_ip;
- ive_video_encode_op_t s_encode_op;
-
- if (!mSpsPpsHeaderReceived) {
- constexpr uint32_t kHeaderLength = MIN_STREAM_SIZE;
- uint8_t header[kHeaderLength];
- error = setEncodeArgs(
- &s_encode_ip, &s_encode_op, NULL, header, kHeaderLength, timestamp);
- if (error != C2_OK) {
- mSignalledError = true;
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return;
- }
- status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
-
- if (IV_SUCCESS != status) {
- ALOGE("Encode header failed = 0x%x\n",
- s_encode_op.u4_error_code);
- return;
- } else {
- ALOGV("Bytes Generated in header %d\n",
- s_encode_op.s_out_buf.u4_bytes);
- }
-
- mSpsPpsHeaderReceived = true;
-
- std::unique_ptr<C2StreamCsdInfo::output> csd =
- C2StreamCsdInfo::output::AllocUnique(s_encode_op.s_out_buf.u4_bytes, 0u);
- memcpy(csd->m.value, header, s_encode_op.s_out_buf.u4_bytes);
- work->worklets.front()->output.configUpdate.push_back(std::move(csd));
-
- DUMP_TO_FILE(
- mOutFile, csd->m.value, csd->flexCount());
- }
-
- if (mUpdateFlag) {
- if (mUpdateFlag & kUpdateBitrate) {
- setBitRate();
- }
- if (mUpdateFlag & kRequestKeyFrame) {
- setFrameType(IV_IDR_FRAME);
- }
- if (mUpdateFlag & kUpdateAIRMode) {
- setAirParams();
- // notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
- // OMX_IndexConfigAndroidIntraRefresh, NULL);
- }
- mUpdateFlag = 0;
- }
-
- if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- mSawInputEOS = true;
- }
-
- /* In normal mode, store inputBufferInfo and this will be returned
- when encoder consumes this input */
- // if (!mInputDataIsMeta && (inputBufferInfo != NULL)) {
- // for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) {
- // if (NULL == mInputBufferInfo[i]) {
- // mInputBufferInfo[i] = inputBufferInfo;
- // break;
- // }
- // }
- // }
- const C2GraphicView view =
- work->input.buffers[0]->data().graphicBlocks().front().map().get();
- if (view.error() != C2_OK) {
- ALOGE("graphic view map err = %d", view.error());
- return;
- }
-
- std::shared_ptr<C2LinearBlock> block;
-
- do {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- // TODO: error handling, proper usage, etc.
- c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
- if (err != C2_OK) {
- ALOGE("fetch linear block err = %d", err);
- work->workletsProcessed = 1u;
- work->result = err;
- return;
- }
- C2WriteView wView = block->map().get();
- if (wView.error() != C2_OK) {
- ALOGE("write view map err = %d", wView.error());
- work->workletsProcessed = 1u;
- work->result = wView.error();
- return;
- }
-
- error = setEncodeArgs(
- &s_encode_ip, &s_encode_op, &view, wView.base(), wView.capacity(), timestamp);
- if (error != C2_OK) {
- mSignalledError = true;
- ALOGE("setEncodeArgs failed : %d", error);
- work->workletsProcessed = 1u;
- work->result = error;
- return;
- }
-
- // DUMP_TO_FILE(
- // mInFile, s_encode_ip.s_inp_buf.apv_bufs[0],
- // (mHeight * mStride * 3 / 2));
-
- GETTIME(&mTimeStart, NULL);
- /* Compute time elapsed between end of previous decode()
- * to start of current decode() */
- TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
- status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
-
- if (IV_SUCCESS != status) {
- if ((s_encode_op.u4_error_code & 0xFF) == IH264E_BITSTREAM_BUFFER_OVERFLOW) {
- // TODO: use IVE_CMD_CTL_GETBUFINFO for proper max input size?
- mOutBufferSize *= 2;
- continue;
- }
- ALOGE("Encode Frame failed = 0x%x\n",
- s_encode_op.u4_error_code);
- mSignalledError = true;
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return;
- }
- } while (IV_SUCCESS != status);
-
- // Hold input buffer reference
- mBuffers[s_encode_ip.s_inp_buf.apv_bufs[0]] = work->input.buffers[0];
-
- GETTIME(&mTimeEnd, NULL);
- /* Compute time taken for decode() */
- TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
-
- ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
- s_encode_op.s_out_buf.u4_bytes);
-
- void *freed = s_encode_op.s_inp_buf.apv_bufs[0];
- /* If encoder frees up an input buffer, mark it as free */
- if (freed != NULL) {
- if (mBuffers.count(freed) == 0u) {
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return;
- }
- // Release input buffer reference
- mBuffers.erase(freed);
-
- auto it = std::find_if(
- mConversionBuffersInUse.begin(), mConversionBuffersInUse.end(),
- [freed](const auto &elem) { return elem.get() == freed; });
- if (it != mConversionBuffersInUse.end()) {
- mFreeConversionBuffers.push_back(std::move(*it));
- mConversionBuffersInUse.erase(it);
- }
- }
-
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->worklets.front()->output.ordinal.timestamp =
- ((uint64_t)s_encode_op.u4_timestamp_high << 32) | s_encode_op.u4_timestamp_low;
- work->worklets.front()->output.buffers.clear();
- std::shared_ptr<C2Buffer> buffer =
- createLinearBuffer(block, 0, s_encode_op.s_out_buf.u4_bytes);
- work->worklets.front()->output.buffers.push_back(buffer);
- work->workletsProcessed = 1u;
-
- if (IV_IDR_FRAME == s_encode_op.u4_encoded_frame_type) {
- buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
- 0u /* stream id */, C2PictureTypeKeyFrame));
- }
-
- if (s_encode_op.u4_is_last) {
- // outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
- mSawOutputEOS = true;
- } else {
- // outputBufferHeader->nFlags &= ~OMX_BUFFERFLAG_EOS;
- }
-}
-
-c2_status_t C2SoftAvcEnc::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- // TODO: use IVE_CMD_CTL_FLUSH?
- (void)drainMode;
- (void)pool;
- return C2_OK;
-}
-
-
-class C2SoftAvcEncFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftAvcEnc(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftAvcEncFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftAvcEncFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h
deleted file mode 100644
index a113436..0000000
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#ifndef C2_SOFT_AVC_ENC_H__
-#define C2_SOFT_AVC_ENC_H__
-
-#include <map>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Vector.h>
-
-#include <SimpleC2Component.h>
-
-namespace android {
-
-#define CODEC_MAX_CORES 4
-#define LEN_STATUS_BUFFER (10 * 1024)
-#define MAX_VBV_BUFF_SIZE (120 * 16384)
-#define MAX_NUM_IO_BUFS 3
-
-#define DEFAULT_MAX_REF_FRM 2
-#define DEFAULT_MAX_REORDER_FRM 0
-#define DEFAULT_QP_MIN 10
-#define DEFAULT_QP_MAX 40
-#define DEFAULT_MAX_BITRATE 20000000
-#define DEFAULT_MAX_SRCH_RANGE_X 256
-#define DEFAULT_MAX_SRCH_RANGE_Y 256
-#define DEFAULT_MAX_FRAMERATE 120000
-#define DEFAULT_NUM_CORES 1
-#define DEFAULT_NUM_CORES_PRE_ENC 0
-#define DEFAULT_FPS 30
-#define DEFAULT_ENC_SPEED IVE_NORMAL
-
-#define DEFAULT_MEM_REC_CNT 0
-#define DEFAULT_RECON_ENABLE 0
-#define DEFAULT_CHKSUM_ENABLE 0
-#define DEFAULT_START_FRM 0
-#define DEFAULT_NUM_FRMS 0xFFFFFFFF
-#define DEFAULT_INP_COLOR_FORMAT IV_YUV_420SP_VU
-#define DEFAULT_RECON_COLOR_FORMAT IV_YUV_420P
-#define DEFAULT_LOOPBACK 0
-#define DEFAULT_SRC_FRAME_RATE 30
-#define DEFAULT_TGT_FRAME_RATE 30
-#define DEFAULT_MAX_WD 1920
-#define DEFAULT_MAX_HT 1920
-#define DEFAULT_MAX_LEVEL 41
-#define DEFAULT_STRIDE 0
-#define DEFAULT_WD 1280
-#define DEFAULT_HT 720
-#define DEFAULT_PSNR_ENABLE 0
-#define DEFAULT_ME_SPEED 100
-#define DEFAULT_ENABLE_FAST_SAD 0
-#define DEFAULT_ENABLE_ALT_REF 0
-#define DEFAULT_RC_MODE IVE_RC_STORAGE
-#define DEFAULT_BITRATE 6000000
-#define DEFAULT_I_QP 22
-#define DEFAULT_I_QP_MAX DEFAULT_QP_MAX
-#define DEFAULT_I_QP_MIN DEFAULT_QP_MIN
-#define DEFAULT_P_QP 28
-#define DEFAULT_P_QP_MAX DEFAULT_QP_MAX
-#define DEFAULT_P_QP_MIN DEFAULT_QP_MIN
-#define DEFAULT_B_QP 22
-#define DEFAULT_B_QP_MAX DEFAULT_QP_MAX
-#define DEFAULT_B_QP_MIN DEFAULT_QP_MIN
-#define DEFAULT_AIR IVE_AIR_MODE_NONE
-#define DEFAULT_AIR_REFRESH_PERIOD 30
-#define DEFAULT_SRCH_RNG_X 64
-#define DEFAULT_SRCH_RNG_Y 48
-#define DEFAULT_I_INTERVAL 30
-#define DEFAULT_IDR_INTERVAL 1000
-#define DEFAULT_B_FRAMES 0
-#define DEFAULT_DISABLE_DEBLK_LEVEL 0
-#define DEFAULT_HPEL 1
-#define DEFAULT_QPEL 1
-#define DEFAULT_I4 1
-#define DEFAULT_EPROFILE IV_PROFILE_BASE
-#define DEFAULT_ENTROPY_MODE 0
-#define DEFAULT_SLICE_MODE IVE_SLICE_MODE_NONE
-#define DEFAULT_SLICE_PARAM 256
-#define DEFAULT_ARCH ARCH_ARM_A9Q
-#define DEFAULT_SOC SOC_GENERIC
-#define DEFAULT_INTRA4x4 0
-#define STRLENGTH 500
-#define DEFAULT_CONSTRAINED_INTRA 0
-
-#define MIN(a, b) ((a) < (b))? (a) : (b)
-#define MAX(a, b) ((a) > (b))? (a) : (b)
-#define ALIGN16(x) ((((x) + 15) >> 4) << 4)
-#define ALIGN128(x) ((((x) + 127) >> 7) << 7)
-#define ALIGN4096(x) ((((x) + 4095) >> 12) << 12)
-
-/** Used to remove warnings about unused parameters */
-#define UNUSED(x) ((void)(x))
-
-/** Get time */
-#define GETTIME(a, b) gettimeofday(a, b);
-
-/** Compute difference between start and end */
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
-#define ive_aligned_malloc(alignment, size) memalign(alignment, size)
-#define ive_aligned_free(buf) free(buf)
-
-struct C2SoftAvcEnc : public SimpleC2Component {
- C2SoftAvcEnc(const char *name, c2_node_id_t id);
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-protected:
- virtual ~C2SoftAvcEnc();
-
-private:
- enum {
- kUpdateBitrate = 1 << 0,
- kRequestKeyFrame = 1 << 1,
- kUpdateAIRMode = 1 << 2,
- };
-
- // OMX input buffer's timestamp and flags
- typedef struct {
- int64_t mTimeUs;
- int32_t mFlags;
- } InputBufferInfo;
-
- int32_t mStride;
-
- struct timeval mTimeStart; // Time at the start of decode()
- struct timeval mTimeEnd; // Time at the end of decode()
-
- int mUpdateFlag;
-
-#ifdef FILE_DUMP_ENABLE
- char mInFile[200];
- char mOutFile[200];
-#endif /* FILE_DUMP_ENABLE */
-
- IV_COLOR_FORMAT_T mIvVideoColorFormat;
-
- IV_PROFILE_T mAVCEncProfile;
- WORD32 mAVCEncLevel;
- bool mStarted;
- bool mSpsPpsHeaderReceived;
-
- bool mSawInputEOS;
- bool mSawOutputEOS;
- bool mSignalledError;
- bool mIntra4x4;
- bool mEnableFastSad;
- bool mEnableAltRef;
- bool mReconEnable;
- bool mPSNREnable;
- bool mEntropyMode;
- bool mConstrainedIntraFlag;
- IVE_SPEED_CONFIG mEncSpeed;
-
- iv_obj_t *mCodecCtx; // Codec context
- iv_mem_rec_t *mMemRecords; // Memory records requested by the codec
- size_t mNumMemRecords; // Number of memory records requested by codec
- size_t mNumCores; // Number of cores used by the codec
-
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFramerate;
- uint32_t mBitrate;
- uint32_t mOutBufferSize;
- UWORD32 mHeaderGenerated;
- UWORD32 mBframes;
- IV_ARCH_T mArch;
- IVE_SLICE_MODE_T mSliceMode;
- UWORD32 mSliceParam;
- bool mHalfPelEnable;
- UWORD32 mIInterval;
- UWORD32 mIDRInterval;
- UWORD32 mDisableDeblkLevel;
- IVE_AIR_MODE_T mAIRMode;
- UWORD32 mAIRRefreshPeriod;
- std::map<const void *, std::shared_ptr<C2Buffer>> mBuffers;
- std::list<std::unique_ptr<uint8_t[]>> mFreeConversionBuffers;
- std::list<std::unique_ptr<uint8_t[]>> mConversionBuffersInUse;
-
- void initEncParams();
- c2_status_t initEncoder();
- c2_status_t releaseEncoder();
-
- c2_status_t setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type);
- c2_status_t setQp();
- c2_status_t setEncMode(IVE_ENC_MODE_T e_enc_mode);
- c2_status_t setDimensions();
- c2_status_t setNumCores();
- c2_status_t setFrameRate();
- c2_status_t setIpeParams();
- c2_status_t setBitRate();
- c2_status_t setAirParams();
- c2_status_t setMeParams();
- c2_status_t setGopParams();
- c2_status_t setProfileParams();
- c2_status_t setDeblockParams();
- c2_status_t setVbvParams();
- void logVersion();
- c2_status_t setEncodeArgs(
- ive_video_encode_ip_t *ps_encode_ip,
- ive_video_encode_op_t *ps_encode_op,
- const C2GraphicView *const input,
- uint8_t *base,
- uint32_t capacity,
- uint64_t timestamp);
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftAvcEnc);
-};
-
-#ifdef FILE_DUMP_ENABLE
-
-#define INPUT_DUMP_PATH "/sdcard/media/avce_input"
-#define INPUT_DUMP_EXT "yuv"
-#define OUTPUT_DUMP_PATH "/sdcard/media/avce_output"
-#define OUTPUT_DUMP_EXT "h264"
-
-#define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
- INPUT_DUMP_EXT); \
- strcpy(mOutFile, ""); \
- sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH,\
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
- OUTPUT_DUMP_EXT); \
-}
-
-#define CREATE_DUMP_FILE(m_filename) { \
- FILE *fp = fopen(m_filename, "wb"); \
- if (fp != NULL) { \
- ALOGD("Opened file %s", m_filename); \
- fclose(fp); \
- } else { \
- ALOGD("Could not open file %s", m_filename); \
- } \
-}
-#define DUMP_TO_FILE(m_filename, m_buf, m_size) \
-{ \
- FILE *fp = fopen(m_filename, "ab"); \
- if (fp != NULL && m_buf != NULL) { \
- int i; \
- i = fwrite(m_buf, 1, m_size, fp); \
- ALOGD("fwrite ret %d to write %d", i, m_size); \
- if (i != (int)m_size) { \
- ALOGD("Error in fwrite, returned %d", i); \
- perror("Error in write to file"); \
- } \
- fclose(fp); \
- } else { \
- ALOGD("Could not write to file %s", m_filename);\
- if (fp != NULL) \
- fclose(fp); \
- } \
-}
-#else /* FILE_DUMP_ENABLE */
-#define INPUT_DUMP_PATH
-#define INPUT_DUMP_EXT
-#define OUTPUT_DUMP_PATH
-#define OUTPUT_DUMP_EXT
-#define GENERATE_FILE_NAMES()
-#define CREATE_DUMP_FILE(m_filename)
-#define DUMP_TO_FILE(m_filename, m_buf, m_size)
-#endif /* FILE_DUMP_ENABLE */
-
-} // namespace android
-
-#endif // C2_SOFT_AVC_ENC_H__
diff --git a/media/libstagefright/codecs/cmds/Android.bp b/media/libstagefright/codecs/cmds/Android.bp
deleted file mode 100644
index 6dba0a3..0000000
--- a/media/libstagefright/codecs/cmds/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-cc_binary {
- name: "codec2",
-
- srcs: [
- "codec2.cpp",
- ],
-
- include_dirs: [
- ],
-
- shared_libs: [
- "libbinder",
- "libcutils",
- "libgui",
- "liblog",
- "libmediaextractor",
- "libstagefright",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libui",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-std=c++14",
- ],
-
-// sanitize: {
-// cfi: true,
-// misc_undefined: [
-// "unsigned-integer-overflow",
-// "signed-integer-overflow",
-// ],
-// diag: {
-// cfi: true,
-// },
-// },
-}
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
deleted file mode 100644
index 295a5b0..0000000
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <inttypes.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <thread>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "codec2"
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <media/DataSource.h>
-#include <media/ICrypto.h>
-#include <media/IMediaHTTPService.h>
-#include <media/MediaExtractor.h>
-#include <media/MediaSource.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractorFactory.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/GLConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <util/C2ParamUtils.h>
-#include <C2AllocatorGralloc.h>
-#include <C2Buffer.h>
-#include <C2BufferPriv.h>
-#include <C2Component.h>
-#include <C2PlatformSupport.h>
-#include <C2Work.h>
-
-using namespace android;
-using namespace std::chrono_literals;
-
-namespace {
-
-class LinearBuffer : public C2Buffer {
-public:
- explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block)
- : C2Buffer({ block->share(block->offset(), block->size(), ::C2Fence()) }) {}
-};
-
-class Listener;
-
-class SimplePlayer {
-public:
- SimplePlayer();
- ~SimplePlayer();
-
- void onWorkDone(std::weak_ptr<C2Component> component,
- std::list<std::unique_ptr<C2Work>> workItems);
- void onTripped(std::weak_ptr<C2Component> component,
- std::vector<std::shared_ptr<C2SettingResult>> settingResult);
- void onError(std::weak_ptr<C2Component> component, uint32_t errorCode);
-
- void play(const sp<IMediaSource> &source);
-
-private:
- typedef std::unique_lock<std::mutex> ULock;
-
- std::shared_ptr<Listener> mListener;
- std::shared_ptr<C2Component> mComponent;
-
- sp<IProducerListener> mProducerListener;
-
- std::atomic_int mLinearPoolId;
-
- std::shared_ptr<C2Allocator> mAllocIon;
- std::shared_ptr<C2BlockPool> mLinearPool;
-
- std::mutex mQueueLock;
- std::condition_variable mQueueCondition;
- std::list<std::unique_ptr<C2Work>> mWorkQueue;
-
- std::mutex mProcessedLock;
- std::condition_variable mProcessedCondition;
- std::list<std::unique_ptr<C2Work>> mProcessedWork;
-
- sp<Surface> mSurface;
- sp<SurfaceComposerClient> mComposerClient;
- sp<SurfaceControl> mControl;
-};
-
-class Listener : public C2Component::Listener {
-public:
- explicit Listener(SimplePlayer *thiz) : mThis(thiz) {}
- virtual ~Listener() = default;
-
- virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,
- std::list<std::unique_ptr<C2Work>> workItems) override {
- mThis->onWorkDone(component, std::move(workItems));
- }
-
- virtual void onTripped_nb(std::weak_ptr<C2Component> component,
- std::vector<std::shared_ptr<C2SettingResult>> settingResult) override {
- mThis->onTripped(component, settingResult);
- }
-
- virtual void onError_nb(std::weak_ptr<C2Component> component,
- uint32_t errorCode) override {
- mThis->onError(component, errorCode);
- }
-
-private:
- SimplePlayer * const mThis;
-};
-
-
-SimplePlayer::SimplePlayer()
- : mListener(new Listener(this)),
- mProducerListener(new DummyProducerListener),
- mLinearPoolId(C2BlockPool::PLATFORM_START),
- mComposerClient(new SurfaceComposerClient) {
- CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
-
- std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
- CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
- mLinearPool = std::make_shared<C2PooledBlockPool>(mAllocIon, mLinearPoolId++);
-
- mControl = mComposerClient->createSurface(
- String8("A Surface"),
- 1280,
- 800,
- HAL_PIXEL_FORMAT_YV12);
- //PIXEL_FORMAT_RGB_565);
-
- CHECK(mControl != NULL);
- CHECK(mControl->isValid());
-
- SurfaceComposerClient::Transaction{}
- .setLayer(mControl, INT_MAX)
- .show(mControl)
- .apply();
-
- mSurface = mControl->getSurface();
- CHECK(mSurface != NULL);
- mSurface->connect(NATIVE_WINDOW_API_CPU, mProducerListener);
-}
-
-SimplePlayer::~SimplePlayer() {
- mComposerClient->dispose();
-}
-
-void SimplePlayer::onWorkDone(
- std::weak_ptr<C2Component> component, std::list<std::unique_ptr<C2Work>> workItems) {
- ALOGV("SimplePlayer::onWorkDone");
- (void) component;
- ULock l(mProcessedLock);
- for (auto & item : workItems) {
- mProcessedWork.push_back(std::move(item));
- }
- mProcessedCondition.notify_all();
-}
-
-void SimplePlayer::onTripped(
- std::weak_ptr<C2Component> component,
- std::vector<std::shared_ptr<C2SettingResult>> settingResult) {
- (void) component;
- (void) settingResult;
- // TODO
-}
-
-void SimplePlayer::onError(std::weak_ptr<C2Component> component, uint32_t errorCode) {
- (void) component;
- (void) errorCode;
- // TODO
-}
-
-void SimplePlayer::play(const sp<IMediaSource> &source) {
- ALOGV("SimplePlayer::play");
- sp<AMessage> format;
- (void) convertMetaDataToMessage(source->getFormat(), &format);
-
- sp<ABuffer> csd0, csd1;
- format->findBuffer("csd-0", &csd0);
- format->findBuffer("csd-1", &csd1);
-
- status_t err = source->start();
-
- if (err != OK) {
- fprintf(stderr, "source returned error %d (0x%08x)\n", err, err);
- return;
- }
-
- std::shared_ptr<C2ComponentStore> store = GetCodec2PlatformComponentStore();
- std::shared_ptr<C2Component> component;
- (void)store->createComponent("c2.google.avc.decoder", &component);
-
- (void)component->setListener_vb(mListener, C2_DONT_BLOCK);
- std::unique_ptr<C2PortBlockPoolsTuning::output> pools =
- C2PortBlockPoolsTuning::output::AllocUnique({ (uint64_t)C2BlockPool::BASIC_GRAPHIC });
- std::vector<std::unique_ptr<C2SettingResult>> result;
- (void)component->intf()->config_vb({pools.get()}, C2_DONT_BLOCK, &result);
- component->start();
-
- for (int i = 0; i < 8; ++i) {
- mWorkQueue.emplace_back(new C2Work);
- }
-
- std::atomic_bool running(true);
- std::thread surfaceThread([this, &running]() {
- const sp<IGraphicBufferProducer> &igbp = mSurface->getIGraphicBufferProducer();
- while (running) {
- std::unique_ptr<C2Work> work;
- {
- ULock l(mProcessedLock);
- if (mProcessedWork.empty()) {
- mProcessedCondition.wait_for(l, 100ms);
- if (mProcessedWork.empty()) {
- continue;
- }
- }
- work.swap(mProcessedWork.front());
- mProcessedWork.pop_front();
- }
- int slot;
- sp<Fence> fence;
- ALOGV("Render: Frame #%lld", work->worklets.front()->output.ordinal.frameIndex.peekll());
- const std::shared_ptr<C2Buffer> &output = work->worklets.front()->output.buffers[0];
- if (output) {
- const C2ConstGraphicBlock block = output->data().graphicBlocks().front();
- native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(block.handle());
- sp<GraphicBuffer> buffer(new GraphicBuffer(
- grallocHandle,
- GraphicBuffer::CLONE_HANDLE,
- block.width(),
- block.height(),
- HAL_PIXEL_FORMAT_YV12,
- 1,
- (uint64_t)GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- block.width()));
- native_handle_delete(grallocHandle);
-
- status_t err = igbp->attachBuffer(&slot, buffer);
-
- IGraphicBufferProducer::QueueBufferInput qbi(
- (work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll(),
- false,
- HAL_DATASPACE_UNKNOWN,
- Rect(block.width(), block.height()),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
- 0,
- Fence::NO_FENCE,
- 0);
- IGraphicBufferProducer::QueueBufferOutput qbo;
- err = igbp->queueBuffer(slot, qbi, &qbo);
- }
-
- work->input.buffers.clear();
- work->worklets.clear();
-
- ULock l(mQueueLock);
- mWorkQueue.push_back(std::move(work));
- mQueueCondition.notify_all();
- }
- ALOGV("render loop finished");
- });
-
- long numFrames = 0;
- mLinearPool.reset(new C2PooledBlockPool(mAllocIon, mLinearPoolId++));
-
- for (;;) {
- size_t size = 0u;
- void *data = nullptr;
- int64_t timestamp = 0u;
- MediaBufferBase *buffer = nullptr;
- sp<ABuffer> csd;
- if (csd0 != nullptr) {
- csd = csd0;
- csd0 = nullptr;
- } else if (csd1 != nullptr) {
- csd = csd1;
- csd1 = nullptr;
- } else {
- status_t err = source->read(&buffer);
- if (err != OK) {
- CHECK(buffer == NULL);
-
- if (err == INFO_FORMAT_CHANGED) {
- continue;
- }
-
- break;
- }
- MetaDataBase &meta = buffer->meta_data();
- CHECK(meta.findInt64(kKeyTime, ×tamp));
-
- size = buffer->size();
- data = buffer->data();
- }
-
- if (csd != nullptr) {
- size = csd->size();
- data = csd->data();
- }
-
- // Prepare C2Work
-
- std::unique_ptr<C2Work> work;
- while (!work) {
- ULock l(mQueueLock);
- if (!mWorkQueue.empty()) {
- work.swap(mWorkQueue.front());
- mWorkQueue.pop_front();
- } else {
- mQueueCondition.wait_for(l, 100ms);
- }
- }
- work->input.flags = (C2FrameData::flags_t)0;
- work->input.ordinal.timestamp = timestamp;
- work->input.ordinal.frameIndex = numFrames;
-
- std::shared_ptr<C2LinearBlock> block;
- mLinearPool->fetchLinearBlock(
- size,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- &block);
- C2WriteView view = block->map().get();
- if (view.error() != C2_OK) {
- fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
- break;
- }
- memcpy(view.base(), data, size);
-
- work->input.buffers.clear();
- work->input.buffers.emplace_back(new LinearBuffer(block));
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
-
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- ALOGV("Frame #%ld size = %zu", numFrames, size);
- // DO THE DECODING
- component->queue_nb(&items);
-
- if (buffer) {
- buffer->release();
- buffer = NULL;
- }
-
- ++numFrames;
- }
- ALOGV("main loop finished");
- source->stop();
- running.store(false);
- surfaceThread.join();
-
- component->release();
- printf("\n");
-}
-
-} // namespace
-
-static void usage(const char *me) {
- fprintf(stderr, "usage: %s [options] [input_filename]\n", me);
- fprintf(stderr, " -h(elp)\n");
-}
-
-int main(int argc, char **argv) {
- android::ProcessState::self()->startThreadPool();
-
- int res;
- while ((res = getopt(argc, argv, "h")) >= 0) {
- switch (res) {
- case 'h':
- default:
- {
- usage(argv[0]);
- exit(1);
- break;
- }
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc < 1) {
- fprintf(stderr, "No input file specified\n");
- return 1;
- }
-
- status_t err = OK;
- SimplePlayer player;
-
- for (int k = 0; k < argc && err == OK; ++k) {
- const char *filename = argv[k];
-
- sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
-
- if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
- fprintf(stderr, "Unable to create data source.\n");
- return 1;
- }
-
- Vector<sp<IMediaSource> > mediaSources;
- sp<IMediaSource> mediaSource;
-
- sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
-
- if (extractor == NULL) {
- fprintf(stderr, "could not create extractor.\n");
- return -1;
- }
-
- sp<MetaData> meta = extractor->getMetaData();
-
- if (meta != NULL) {
- const char *mime;
- if (!meta->findCString(kKeyMIMEType, &mime)) {
- fprintf(stderr, "extractor did not provide MIME type.\n");
- return -1;
- }
- }
-
- size_t numTracks = extractor->countTracks();
-
- size_t i;
- for (i = 0; i < numTracks; ++i) {
- meta = extractor->getTrackMetaData(
- i, MediaExtractor::kIncludeExtensiveMetaData);
-
- if (meta == NULL) {
- break;
- }
- const char *mime;
- meta->findCString(kKeyMIMEType, &mime);
-
- // TODO: allowing AVC only for the time being
- if (!strncasecmp(mime, "video/avc", 9)) {
- break;
- }
-
- meta = NULL;
- }
-
- if (meta == NULL) {
- fprintf(stderr, "No AVC track found.\n");
- return -1;
- }
-
- mediaSource = extractor->getTrack(i);
- if (mediaSource == nullptr) {
- fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
- return -1;
- }
-
- player.play(mediaSource);
- }
-
- return 0;
-}
diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp
index 68fdd15..9af086b 100644
--- a/media/libstagefright/codecs/flac/dec/Android.bp
+++ b/media/libstagefright/codecs/flac/dec/Android.bp
@@ -1,48 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2flacdec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: [
- "C2SoftFlacDecoder.cpp",
- ],
-
- include_dirs: [
- "external/flac/include",
- "frameworks/av/media/libstagefright/flac/dec",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_flacdec",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-}
-
-
-cc_library_shared {
name: "libstagefright_soft_flacdec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.cpp
deleted file mode 100644
index 0f1fecc..0000000
--- a/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftFlacDecoder"
-#include <utils/Log.h>
-
-#include "C2SoftFlacDecoder.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.flac.decoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatAudio)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_FLAC)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-C2SoftFlacDecoder::C2SoftFlacDecoder(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mFLACDecoder(nullptr) {
-}
-
-C2SoftFlacDecoder::~C2SoftFlacDecoder() {
-}
-
-c2_status_t C2SoftFlacDecoder::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_NO_MEMORY;
-}
-
-c2_status_t C2SoftFlacDecoder::onStop() {
- if (mFLACDecoder) mFLACDecoder->flush();
- memset(&mStreamInfo, 0, sizeof(mStreamInfo));
- mHasStreamInfo = false;
- mSignalledError = false;
- mSignalledOutputEos = false;
- mInputBufferCount = 0;
- return C2_OK;
-}
-
-void C2SoftFlacDecoder::onReset() {
- (void)onStop();
-}
-
-void C2SoftFlacDecoder::onRelease() {
-}
-
-c2_status_t C2SoftFlacDecoder::onFlush_sm() {
- return onStop();
-}
-
-status_t C2SoftFlacDecoder::initDecoder() {
- mFLACDecoder = FLACDecoder::Create();
- if (!mFLACDecoder) {
- ALOGE("initDecoder: failed to create FLACDecoder");
- mSignalledError = true;
- return NO_MEMORY;
- }
-
- memset(&mStreamInfo, 0, sizeof(mStreamInfo));
- mHasStreamInfo = false;
- mSignalledError = false;
- mSignalledOutputEos = false;
- mInputBufferCount = 0;
-
- return OK;
-}
-
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-// (TODO) add multiframe support, in plugin and FLACDecoder.cpp
-void C2SoftFlacDecoder::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
- bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
- (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
-
- if (inSize == 0) {
- fillEmptyWork(work);
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- return;
- }
-
- if (mInputBufferCount == 0 && !codecConfig) {
- ALOGV("First frame has to include configuration, forcing config");
- codecConfig = true;
- }
-
- uint8_t *input = const_cast<uint8_t *>(rView.data() + inOffset);
- if (codecConfig) {
- status_t decoderErr = mFLACDecoder->parseMetadata(input, inSize);
- if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
- ALOGE("process: FLACDecoder parseMetaData returns error %d", decoderErr);
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
-
- mInputBufferCount++;
- fillEmptyWork(work);
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
-
- if (decoderErr == WOULD_BLOCK) {
- ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
- } else {
- mStreamInfo = mFLACDecoder->getStreamInfo();
- if (mStreamInfo.max_blocksize && mStreamInfo.channels)
- mHasStreamInfo = true;
- ALOGD("process: decoder configuration : %d Hz, %d channels, %d samples,"
- " %d block size", mStreamInfo.sample_rate, mStreamInfo.channels,
- (int)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
- }
- return;
- }
-
- size_t outSize;
- if (mHasStreamInfo)
- outSize = mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(short);
- else
- outSize = kMaxBlockSize * FLACDecoder::kMaxChannels * sizeof(short);
-
- std::shared_ptr<C2LinearBlock> block;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = block->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- short *output = reinterpret_cast<short *>(wView.data());
- status_t decoderErr = mFLACDecoder->decodeOneFrame(
- input, inSize, output, &outSize);
- if (decoderErr != OK) {
- ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
-
- mInputBufferCount++;
- ALOGV("out buffer attr. size %zu", outSize);
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
-}
-
-c2_status_t C2SoftFlacDecoder::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- if (mFLACDecoder) mFLACDecoder->flush();
-
- return C2_OK;
-}
-
-class C2SoftFlacDecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftFlacDecoder(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftFlacDecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftFlacDecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.h
deleted file mode 100644
index a5c01a9..0000000
--- a/media/libstagefright/codecs/flac/dec/C2SoftFlacDecoder.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_FLAC_DECODER_H_
-#define C2_SOFT_FLAC_DECODER_H_
-
-#include <SimpleC2Component.h>
-
-#include "FLACDecoder.h"
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct C2SoftFlacDecoder : public SimpleC2Component {
- C2SoftFlacDecoder(const char *name, c2_node_id_t id);
- virtual ~C2SoftFlacDecoder();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- enum {
- kMaxBlockSize = 4096
- };
-
- sp<FLACDecoder> mFLACDecoder;
- FLAC__StreamMetadata_StreamInfo mStreamInfo;
- bool mSignalledError;
- bool mSignalledOutputEos;
- bool mHasStreamInfo;
- size_t mInputBufferCount;
-
- status_t initDecoder();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftFlacDecoder);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_FLAC_DECODER_H_
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index 4ab1ab2..d0b72b7 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -57,6 +57,7 @@
SoftFlacDecoder::~SoftFlacDecoder() {
ALOGV("dtor:");
+ delete mFLACDecoder;
}
void SoftFlacDecoder::initPorts() {
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
index 4a21c34..0f17ed8 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -50,7 +50,7 @@
kNumOutputBuffers = 4,
};
- sp<FLACDecoder> mFLACDecoder;
+ FLACDecoder *mFLACDecoder;
FLAC__StreamMetadata_StreamInfo mStreamInfo;
bool mHasStreamInfo;
size_t mInputBufferCount;
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index bb705dd..46b974d 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -1,43 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2flacenc",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftFlacEnc.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: [
- "libFLAC",
- ],
-
- shared_libs: [
- "liblog",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libutils",
- ],
-}
-
-cc_library_shared {
srcs: ["SoftFlacEncoder.cpp"],
diff --git a/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.cpp b/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.cpp
deleted file mode 100644
index fa93fe5..0000000
--- a/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftFlacEnc"
-#include <utils/Log.h>
-
-#include "C2SoftFlacEnc.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.flac.encoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatAudio)
- .outputFormat(C2FormatCompressed)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_FLAC)
- .build();
-}
-
-C2SoftFlacEnc::C2SoftFlacEnc(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mFlacStreamEncoder(nullptr),
- mInputBufferPcm32(nullptr) {
-}
-
-C2SoftFlacEnc::~C2SoftFlacEnc() {
- onRelease();
-}
-
-c2_status_t C2SoftFlacEnc::onInit() {
- mFlacStreamEncoder = FLAC__stream_encoder_new();
- if (!mFlacStreamEncoder) return C2_CORRUPTED;
-
- mInputBufferPcm32 = (FLAC__int32*) malloc(
- kInBlockSize * kMaxNumChannels * sizeof(FLAC__int32));
- if (!mInputBufferPcm32) return C2_NO_MEMORY;
-
- mSignalledError = false;
- mSignalledOutputEos = false;
- mNumChannels = 1;
- mSampleRate = 44100;
- mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
- mIsFirstFrame = true;
- mAnchorTimeStamp = 0ull;
- mProcessedSamples = 0u;
- mEncoderWriteData = false;
- mEncoderReturnedNbBytes = 0;
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- mHeaderOffset = 0;
- mWroteHeader = false;
-#endif
-
- status_t err = configureEncoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-void C2SoftFlacEnc::onRelease() {
- if (mFlacStreamEncoder) {
- FLAC__stream_encoder_delete(mFlacStreamEncoder);
- mFlacStreamEncoder = nullptr;
- }
-
- if (mInputBufferPcm32) {
- free(mInputBufferPcm32);
- mInputBufferPcm32 = nullptr;
- }
-}
-
-void C2SoftFlacEnc::onReset() {
- mNumChannels = 1;
- mSampleRate = 44100;
- mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
- (void) onStop();
-}
-
-c2_status_t C2SoftFlacEnc::onStop() {
- mSignalledError = false;
- mSignalledOutputEos = false;
- mIsFirstFrame = true;
- mAnchorTimeStamp = 0ull;
- mProcessedSamples = 0u;
- mEncoderWriteData = false;
- mEncoderReturnedNbBytes = 0;
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- mHeaderOffset = 0;
- mWroteHeader = false;
-#endif
-
- c2_status_t status = drain(DRAIN_COMPONENT_NO_EOS, nullptr);
- if (C2_OK != status) return status;
-
- status_t err = configureEncoder();
- if (err != OK) mSignalledError = true;
- return C2_OK;
-}
-
-c2_status_t C2SoftFlacEnc::onFlush_sm() {
- return onStop();
-}
-
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-void C2SoftFlacEnc::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
- inSize, (int)work->input.ordinal.timestamp.peeku(),
- (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
- if (mIsFirstFrame && inSize) {
- mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
- mIsFirstFrame = false;
- }
- uint64_t outTimeStamp = mProcessedSamples * 1000000ll / mSampleRate;
-
- size_t outCapacity = inSize;
- outCapacity += mBlockSize * mNumChannels * sizeof(int16_t);
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- outCapacity += FLAC_HEADER_SIZE;
-#endif
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &mOutputBlock);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = mOutputBlock->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- mEncoderWriteData = true;
- mEncoderReturnedNbBytes = 0;
- while (inOffset < inSize) {
- size_t processSize = MIN(kInBlockSize * mNumChannels * sizeof(int16_t), (inSize - inOffset));
- const unsigned nbInputFrames = processSize / (mNumChannels * sizeof(int16_t));
- const unsigned nbInputSamples = processSize / sizeof(int16_t);
- const int16_t *pcm16 = reinterpret_cast<const int16_t *>(rView.data() + inOffset);
- ALOGV("about to encode %zu bytes", processSize);
-
- for (unsigned i = 0; i < nbInputSamples; i++) {
- mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
- }
-
- FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
- mFlacStreamEncoder, mInputBufferPcm32, nbInputFrames);
- if (!ok) {
- ALOGE("error encountered during encoding");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- mOutputBlock.reset();
- return;
- }
- inOffset += processSize;
- }
- if (eos && !drain(DRAIN_COMPONENT_WITH_EOS, pool)) {
- ALOGE("error encountered during encoding");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- mOutputBlock.reset();
- return;
- }
- fillEmptyWork(work);
- if (mEncoderReturnedNbBytes != 0) {
- std::shared_ptr<C2Buffer> buffer = createLinearBuffer(std::move(mOutputBlock), 0, mEncoderReturnedNbBytes);
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
- } else {
- ALOGV("encoder process_interleaved returned without data to write");
- }
- mOutputBlock = nullptr;
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- mEncoderWriteData = false;
- mEncoderReturnedNbBytes = 0;
-}
-
-FLAC__StreamEncoderWriteStatus C2SoftFlacEnc::onEncodedFlacAvailable(
- const FLAC__byte buffer[], size_t bytes, unsigned samples,
- unsigned current_frame) {
- (void) current_frame;
- ALOGV("%s (bytes=%zu, samples=%u, curr_frame=%u)", __func__, bytes, samples,
- current_frame);
-
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- if (samples == 0) {
- ALOGI("saving %zu bytes of header", bytes);
- memcpy(mHeader + mHeaderOffset, buffer, bytes);
- mHeaderOffset += bytes;// will contain header size when finished receiving header
- return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
- }
-#endif
-
- if ((samples == 0) || !mEncoderWriteData) {
- // called by the encoder because there's header data to save, but it's not the role
- // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
- ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
- return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
- }
-
- // write encoded data
- C2WriteView wView = mOutputBlock->map().get();
- uint8_t* outData = wView.data();
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- if (!mWroteHeader) {
- ALOGI("writing %d bytes of header on output", mHeaderOffset);
- memcpy(outData + mEncoderReturnedNbBytes, mHeader, mHeaderOffset);
- mEncoderReturnedNbBytes += mHeaderOffset;
- mWroteHeader = true;
- }
-#endif
- ALOGV("writing %zu bytes of encoded data on output", bytes);
- // increment mProcessedSamples to maintain audio synchronization during
- // play back
- mProcessedSamples += samples;
- if (bytes + mEncoderReturnedNbBytes > mOutputBlock->capacity()) {
- ALOGE("not enough space left to write encoded data, dropping %zu bytes", bytes);
- // a fatal error would stop the encoding
- return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
- }
- memcpy(outData + mEncoderReturnedNbBytes, buffer, bytes);
- mEncoderReturnedNbBytes += bytes;
- return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
-}
-
-
-status_t C2SoftFlacEnc::configureEncoder() {
- ALOGV("%s numChannel=%d, sampleRate=%d", __func__, mNumChannels, mSampleRate);
-
- if (mSignalledError || !mFlacStreamEncoder) {
- ALOGE("can't configure encoder: no encoder or invalid state");
- return UNKNOWN_ERROR;
- }
-
- FLAC__bool ok = true;
- ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
- ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
- ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
- ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, mCompressionLevel);
- ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
- if (!ok) {
- ALOGE("unknown error when configuring encoder");
- return UNKNOWN_ERROR;
- }
-
- ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
- FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
- flacEncoderWriteCallback /*write_callback*/,
- nullptr /*seek_callback*/,
- nullptr /*tell_callback*/,
- nullptr /*metadata_callback*/,
- (void *) this /*client_data*/);
-
- if (!ok) {
- ALOGE("unknown error when configuring encoder");
- return UNKNOWN_ERROR;
- }
-
- mBlockSize = FLAC__stream_encoder_get_blocksize(mFlacStreamEncoder);
-
- ALOGV("encoder successfully configured");
- return OK;
-}
-
-FLAC__StreamEncoderWriteStatus C2SoftFlacEnc::flacEncoderWriteCallback(
- const FLAC__StreamEncoder *,
- const FLAC__byte buffer[],
- size_t bytes,
- unsigned samples,
- unsigned current_frame,
- void *client_data) {
- return ((C2SoftFlacEnc*) client_data)->onEncodedFlacAvailable(
- buffer, bytes, samples, current_frame);
-}
-
-c2_status_t C2SoftFlacEnc::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- switch (drainMode) {
- case NO_DRAIN:
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- case DRAIN_CHAIN:
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- case DRAIN_COMPONENT_WITH_EOS:
- // TODO: This flag is not being sent back to the client
- // because there are no items in PendingWork queue as all the
- // inputs are being sent back with emptywork or valid encoded data
- // mSignalledOutputEos = true;
- case DRAIN_COMPONENT_NO_EOS:
- break;
- default:
- return C2_BAD_VALUE;
- }
- FLAC__bool ok = FLAC__stream_encoder_finish(mFlacStreamEncoder);
- if (!ok) return C2_CORRUPTED;
- mIsFirstFrame = true;
- mAnchorTimeStamp = 0ull;
- mProcessedSamples = 0u;
-
- return C2_OK;
-}
-
-class C2SoftFlacEncFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftFlacEnc(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftFlacEncFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftFlacEncFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.h b/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.h
deleted file mode 100644
index cc8cb86..0000000
--- a/media/libstagefright/codecs/flac/enc/C2SoftFlacEnc.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_FLAC_ENC_H_
-#define C2_SOFT_FLAC_ENC_H_
-
-#include <SimpleC2Component.h>
-
-#include "FLAC/stream_encoder.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-// use this symbol to have the first output buffer start with FLAC frame header so a dump of
-// all the output buffers can be opened as a .flac file
-//#define WRITE_FLAC_HEADER_IN_FIRST_BUFFER
-
-#define FLAC_COMPRESSION_LEVEL_MIN 0
-#define FLAC_COMPRESSION_LEVEL_DEFAULT 5
-#define FLAC_COMPRESSION_LEVEL_MAX 8
-
-#define FLAC_HEADER_SIZE 128
-
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-
-namespace android {
-
-class C2SoftFlacEnc : public SimpleC2Component {
-public:
- C2SoftFlacEnc(const char *name, c2_node_id_t id);
- virtual ~C2SoftFlacEnc();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- status_t configureEncoder();
- static FLAC__StreamEncoderWriteStatus flacEncoderWriteCallback(
- const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[],
- size_t bytes, unsigned samples, unsigned current_frame,
- void *client_data);
- FLAC__StreamEncoderWriteStatus onEncodedFlacAvailable(
- const FLAC__byte buffer[], size_t bytes, unsigned samples,
- unsigned current_frame);
-
- const unsigned int kInBlockSize = 1152;
- const unsigned int kMaxNumChannels = 2;
- FLAC__StreamEncoder* mFlacStreamEncoder;
- FLAC__int32* mInputBufferPcm32;
- std::shared_ptr<C2LinearBlock> mOutputBlock;
- bool mSignalledError;
- bool mSignalledOutputEos;
- uint32_t mNumChannels;
- uint32_t mSampleRate;
- uint32_t mCompressionLevel;
- uint32_t mBlockSize;
- bool mIsFirstFrame;
- uint64_t mAnchorTimeStamp;
- uint64_t mProcessedSamples;
- // should the data received by the callback be written to the output port
- bool mEncoderWriteData;
- size_t mEncoderReturnedNbBytes;
-#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
- unsigned mHeaderOffset;
- bool mWroteHeader;
- char mHeader[FLAC_HEADER_SIZE];
-#endif
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftFlacEnc);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_FLAC_ENC_H_
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index 58a0a4d..3d97d8c 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -1,79 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2g711alawdec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: [
- "C2SoftG711.cpp",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-DALAW",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-}
-
-cc_library_shared {
- name: "libstagefright_soft_c2g711mlawdec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: [
- "C2SoftG711.cpp",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-}
-
-cc_library_shared {
name: "libstagefright_soft_g711dec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
deleted file mode 100644
index 1049420..0000000
--- a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftG711"
-#include <utils/Log.h>
-
-#include "C2SoftG711.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-#ifdef ALAW
-constexpr char kComponentName[] = "c2.google.g711.alaw.decoder";
-#else
-constexpr char kComponentName[] = "c2.google.g711.mlaw.decoder";
-#endif
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatAudio)
- .inputMediaType(
-#ifdef ALAW
- MEDIA_MIMETYPE_AUDIO_G711_ALAW
-#else
- MEDIA_MIMETYPE_AUDIO_G711_MLAW
-#endif
- )
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-
-C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)) {
-}
-
-C2SoftG711::~C2SoftG711() {
- onRelease();
-}
-
-c2_status_t C2SoftG711::onInit() {
- mSignalledOutputEos = false;
- return C2_OK;
-}
-
-c2_status_t C2SoftG711::onStop() {
- mSignalledOutputEos = false;
- return C2_OK;
-}
-
-void C2SoftG711::onReset() {
- (void)onStop();
-}
-
-void C2SoftG711::onRelease() {
-}
-
-c2_status_t C2SoftG711::onFlush_sm() {
- return onStop();
-}
-
-void C2SoftG711::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer =
- work->input.buffers[0]->data().linearBlocks().front();
- C2ReadView rView = inBuffer.map().get();
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- int outSize = inSize * sizeof(int16_t);
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
- (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
-
- if (inSize == 0) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- return;
- }
-
- uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
-
- std::shared_ptr<C2LinearBlock> block;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = block->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
-
-#ifdef ALAW
- DecodeALaw(outputptr, inputptr, inSize);
-#else
- DecodeMLaw(outputptr, inputptr, inSize);
-#endif
-
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
-}
-
-c2_status_t C2SoftG711::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- return C2_OK;
-}
-
-#ifdef ALAW
-void C2SoftG711::DecodeALaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize > 0) {
- inSize--;
- int32_t x = *in++;
-
- int32_t ix = x ^ 0x55;
- ix &= 0x7f;
-
- int32_t iexp = ix >> 4;
- int32_t mant = ix & 0x0f;
-
- if (iexp > 0) {
- mant += 16;
- }
-
- mant = (mant << 4) + 8;
-
- if (iexp > 1) {
- mant = mant << (iexp - 1);
- }
-
- *out++ = (x > 127) ? mant : -mant;
- }
-}
-#else
-void C2SoftG711::DecodeMLaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize > 0) {
- inSize--;
- int32_t x = *in++;
-
- int32_t mantissa = ~x;
- int32_t exponent = (mantissa >> 4) & 7;
- int32_t segment = exponent + 1;
- mantissa &= 0x0f;
-
- int32_t step = 4 << segment;
-
- int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
-
- *out++ = (x < 0x80) ? -abs : abs;
- }
-}
-#endif
-
-class C2SoftG711DecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftG711(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftG711DecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftG711DecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.h b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
deleted file mode 100644
index eed38c9..0000000
--- a/media/libstagefright/codecs/g711/dec/C2SoftG711.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_G711_H_
-#define C2_SOFT_G711_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct C2SoftG711 : public SimpleC2Component {
- C2SoftG711(const char *name, c2_node_id_t id);
- virtual ~C2SoftG711();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-private:
- bool mSignalledOutputEos;
-
-#ifdef ALAW
- void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
-#else
- void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
-#endif
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftG711);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_G711_H_
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index d24a116..ca70cc2 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -112,91 +112,3 @@
},
compile_multilib: "32",
}
-
-//###############################################################################
-
-cc_library_shared {
- name: "libstagefright_soft_c2mpeg4dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftMpeg4Dec.cpp"],
-
- cflags: [
- "-DOSCL_IMPORT_REF=",
- "-DMPEG4",
- "-Wall",
- "-Werror",
- ],
-
- local_include_dirs: ["src"],
- export_include_dirs: ["include"],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: ["libstagefright_m4vh263dec"],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-//###############################################################################
-cc_library_shared {
- name: "libstagefright_soft_c2h263dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftMpeg4Dec.cpp"],
-
- cflags: [
- "-DOSCL_IMPORT_REF=",
- "-Wall",
- "-Werror",
- ],
-
- local_include_dirs: ["src"],
- export_include_dirs: ["include"],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: ["libstagefright_m4vh263dec"],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.cpp b/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.cpp
deleted file mode 100644
index 641c342..0000000
--- a/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftMpeg4Dec"
-#include <utils/Log.h>
-
-#include "C2SoftMpeg4Dec.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-#include "mp4dec_api.h"
-
-namespace android {
-
-#ifdef MPEG4
-constexpr char kComponentName[] = "c2.google.mpeg4.decoder";
-#else
-constexpr char kComponentName[] = "c2.google.h263.decoder";
-#endif
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatVideo)
- .inputMediaType(
-#ifdef MPEG4
- MEDIA_MIMETYPE_VIDEO_MPEG4
-#else
- MEDIA_MIMETYPE_VIDEO_H263
-#endif
- )
- .outputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
- .build();
-}
-
-C2SoftMpeg4Dec::C2SoftMpeg4Dec(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mDecHandle(nullptr) {
-}
-
-C2SoftMpeg4Dec::~C2SoftMpeg4Dec() {
- onRelease();
-}
-
-c2_status_t C2SoftMpeg4Dec::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-c2_status_t C2SoftMpeg4Dec::onStop() {
- if (mInitialized) {
- PVCleanUpVideoDecoder(mDecHandle);
- mInitialized = false;
- }
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- if (mOutputBuffer[i]) {
- free(mOutputBuffer[i]);
- mOutputBuffer[i] = nullptr;
- }
- }
- mNumSamplesOutput = 0;
- mFramesConfigured = false;
- mSignalledOutputEos = false;
- mSignalledError = false;
-
- return C2_OK;
-}
-
-void C2SoftMpeg4Dec::onReset() {
- (void) onStop();
-}
-
-void C2SoftMpeg4Dec::onRelease() {
- if (mInitialized) {
- PVCleanUpVideoDecoder(mDecHandle);
- }
- if (mOutBlock) {
- mOutBlock.reset();
- }
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- if (mOutputBuffer[i]) {
- free(mOutputBuffer[i]);
- mOutputBuffer[i] = nullptr;
- }
- }
-
- delete mDecHandle;
- mDecHandle = nullptr;
-}
-
-c2_status_t C2SoftMpeg4Dec::onFlush_sm() {
- if (mInitialized) {
- if (PV_TRUE != PVResetVideoDecoder(mDecHandle)) return C2_CORRUPTED;
- }
- mSignalledOutputEos = false;
- mSignalledError = false;
- return C2_OK;
-}
-
-status_t C2SoftMpeg4Dec::initDecoder() {
-#ifdef MPEG4
- mIsMpeg4 = true;
-#else
- mIsMpeg4 = false;
-#endif
- if (!mDecHandle) {
- mDecHandle = new tagvideoDecControls;
- }
- memset(mDecHandle, 0, sizeof(tagvideoDecControls));
-
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- mOutputBuffer[i] = nullptr;
- }
-
- /* TODO: bring these values to 352 and 288. It cannot be done as of now
- * because, h263 doesn't seem to allow port reconfiguration. In OMX, the
- * problem of larger width and height than default width and height is
- * overcome by adaptivePlayBack() api call. This call gets width and height
- * information from extractor. Such a thing is not possible here.
- * So we are configuring to larger values.*/
- mWidth = 1408;
- mHeight = 1152;
- mNumSamplesOutput = 0;
- mInitialized = false;
- mFramesConfigured = false;
- mSignalledOutputEos = false;
- mSignalledError = false;
-
- return OK;
-}
-
-void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-void C2SoftMpeg4Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
- std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
- C2Rect(mWidth, mHeight));
- mOutBlock = nullptr;
- auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
- (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
- fillWork(work);
- } else {
- finish(index, fillWork);
- }
-}
-
-c2_status_t C2SoftMpeg4Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
- if (!mDecHandle) {
- ALOGE("not supposed to be here, invalid decoder context");
- return C2_CORRUPTED;
- }
-
- uint32_t outSize = align(mWidth, 16) * align(mHeight, 16) * 3 / 2;
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- if (!mOutputBuffer[i]) {
- mOutputBuffer[i] = (uint8_t *)malloc(outSize * sizeof(uint8_t));
- if (!mOutputBuffer[i]) return C2_NO_MEMORY;
- }
- }
- if (mOutBlock &&
- (mOutBlock->width() != align(mWidth, 16) || mOutBlock->height() != mHeight)) {
- mOutBlock.reset();
- }
- if (!mOutBlock) {
- uint32_t format = HAL_PIXEL_FORMAT_YV12;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &mOutBlock);
- if (err != C2_OK) {
- ALOGE("fetchGraphicBlock for Output failed with status %d", err);
- return err;
- }
- ALOGV("provided (%dx%d) required (%dx%d)",
- mOutBlock->width(), mOutBlock->height(), mWidth, mHeight);
- }
- return C2_OK;
-}
-
-bool C2SoftMpeg4Dec::handleResChange(const std::unique_ptr<C2Work> &work) {
- uint32_t disp_width, disp_height;
- PVGetVideoDimensions(mDecHandle, (int32 *)&disp_width, (int32 *)&disp_height);
-
- uint32_t buf_width, buf_height;
- PVGetBufferDimensions(mDecHandle, (int32 *)&buf_width, (int32 *)&buf_height);
-
- CHECK_LE(disp_width, buf_width);
- CHECK_LE(disp_height, buf_height);
-
- ALOGV("display size (%dx%d), buffer size (%dx%d)",
- disp_width, disp_height, buf_width, buf_height);
-
- bool resChanged = false;
- if (disp_width != mWidth || disp_height != mHeight) {
- mWidth = disp_width;
- mHeight = disp_height;
- resChanged = true;
- for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
- if (mOutputBuffer[i]) {
- free(mOutputBuffer[i]);
- mOutputBuffer[i] = nullptr;
- }
- }
-
- if (!mIsMpeg4) {
- PVCleanUpVideoDecoder(mDecHandle);
-
- uint8_t *vol_data[1]{};
- int32_t vol_size = 0;
-
- if (!PVInitVideoDecoder(
- mDecHandle, vol_data, &vol_size, 1, mWidth, mHeight, H263_MODE)) {
- ALOGE("Error in PVInitVideoDecoder H263_MODE while resChanged was set to true");
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return true;
- }
- }
- mFramesConfigured = false;
- }
- return resChanged;
-}
-
-/* TODO: can remove temporary copy after library supports writing to display
- * buffer Y, U and V plane pointers using stride info. */
-static void copyOutputBufferToYV12Frame(uint8_t *dst, uint8_t *src, size_t dstYStride,
- size_t srcYStride, uint32_t width, uint32_t height) {
- size_t dstUVStride = align(dstYStride / 2, 16);
- size_t srcUVStride = srcYStride / 2;
- uint8_t *srcStart = src;
- uint8_t *dstStart = dst;
- size_t vStride = align(height, 16);
- for (size_t i = 0; i < height; ++i) {
- memcpy(dst, src, width);
- src += srcYStride;
- dst += dstYStride;
- }
- /* U buffer */
- src = srcStart + vStride * srcYStride;
- dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dst, src, width / 2);
- src += srcUVStride;
- dst += dstUVStride;
- }
- /* V buffer */
- src = srcStart + vStride * srcYStride * 5 / 4;
- dst = dstStart + (dstYStride * height);
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dst, src, width / 2);
- src += srcUVStride;
- dst += dstUVStride;
- }
-}
-
-void C2SoftMpeg4Dec::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
- inSize, (int)work->input.ordinal.timestamp.peeku(),
- (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
-
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- if (inSize == 0) {
- fillEmptyWork(work);
- if (eos) {
- mSignalledOutputEos = true;
- }
- return;
- }
-
- uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
- uint32_t *start_code = (uint32_t *)bitstream;
- bool volHeader = *start_code == 0xB0010000;
- if (volHeader) {
- PVCleanUpVideoDecoder(mDecHandle);
- mInitialized = false;
- }
-
- if (!mInitialized) {
- uint8_t *vol_data[1]{};
- int32_t vol_size = 0;
-
- bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
- if (codecConfig || volHeader) {
- vol_data[0] = bitstream;
- vol_size = inSize;
- }
- MP4DecodingMode mode = (mIsMpeg4) ? MPEG4_MODE : H263_MODE;
-
- if (!PVInitVideoDecoder(
- mDecHandle, vol_data, &vol_size, 1,
- mWidth, mHeight, mode)) {
- ALOGE("PVInitVideoDecoder failed. Unsupported content?");
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
- mInitialized = true;
- MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
- if (mode != actualMode) {
- ALOGE("Decoded mode not same as actual mode of the decoder");
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
-
- PVSetPostProcType(mDecHandle, 0);
- (void) handleResChange(work);
- if (codecConfig) {
- fillEmptyWork(work);
- return;
- }
- }
-
- while (inOffset < inSize) {
- c2_status_t err = ensureDecoderState(pool);
- if (C2_OK != err) {
- mSignalledError = true;
- work->result = err;
- return;
- }
- C2GraphicView wView = mOutBlock->map().get();
- if (wView.error()) {
- ALOGE("graphic view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- uint32_t outSize = align(mWidth, 16) * align(mHeight, 16) * 3 / 2;
- uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
- if (outSize < yFrameSize * 3 / 2){
- ALOGE("Too small output buffer: %d bytes", outSize);
- work->result = C2_NO_MEMORY;
- mSignalledError = true;
- return;
- }
-
- if (!mFramesConfigured) {
- PVSetReferenceYUV(mDecHandle,mOutputBuffer[1]);
- mFramesConfigured = true;
- }
-
- // Need to check if header contains new info, e.g., width/height, etc.
- VopHeaderInfo header_info;
- uint32_t useExtTimestamp = (inOffset == 0);
- int32_t tmpInSize = (int32_t)inSize;
- uint8_t *bitstreamTmp = bitstream;
- uint32_t timestamp = workIndex;
- if (PVDecodeVopHeader(
- mDecHandle, &bitstreamTmp, ×tamp, &tmpInSize,
- &header_info, &useExtTimestamp,
- mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
- ALOGE("failed to decode vop header.");
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
-
- // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
- // decoder may detect size change after PVDecodeVopHeader.
- bool resChange = handleResChange(work);
- if (mIsMpeg4 && resChange) {
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- } else if (resChange) {
- continue;
- }
-
- if (PVDecodeVopBody(mDecHandle, &tmpInSize) != PV_TRUE) {
- ALOGE("failed to decode video frame.");
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
- if (handleResChange(work)) {
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
-
- uint8_t *outputBufferY = wView.data()[C2PlanarLayout::PLANE_Y];
- (void)copyOutputBufferToYV12Frame(outputBufferY, mOutputBuffer[mNumSamplesOutput & 1],
- wView.width(), align(mWidth, 16), mWidth, mHeight);
-
- inOffset += inSize - (size_t)tmpInSize;
- finishWork(workIndex, work);
- ++mNumSamplesOutput;
- if (inSize - inOffset) {
- ALOGD("decoded frame, ignoring further trailing bytes %zu",
- inSize - (size_t)tmpInSize);
- break;
- }
- }
-}
-
-c2_status_t C2SoftMpeg4Dec::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
- return C2_OK;
-}
-
-class C2SoftMpeg4DecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftMpeg4Dec(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftMpeg4DecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftMpeg4DecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.h b/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.h
deleted file mode 100644
index 8eb316e..0000000
--- a/media/libstagefright/codecs/m4v_h263/dec/C2SoftMpeg4Dec.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_MPEG4_DEC_H_
-#define C2_SOFT_MPEG4_DEC_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-struct tagvideoDecControls;
-
-namespace android {
-
-struct C2SoftMpeg4Dec : public SimpleC2Component {
- C2SoftMpeg4Dec(const char *name, c2_node_id_t id);
- virtual ~C2SoftMpeg4Dec();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
- private:
- enum {
- kNumOutputBuffers = 2,
- };
-
- status_t initDecoder();
- c2_status_t ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool);
- void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work);
- bool handleResChange(const std::unique_ptr<C2Work> &work);
-
- tagvideoDecControls *mDecHandle;
- std::shared_ptr<C2GraphicBlock> mOutBlock;
- uint8_t *mOutputBuffer[kNumOutputBuffers];
-
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mNumSamplesOutput;
-
- bool mIsMpeg4;
- bool mInitialized;
- bool mFramesConfigured;
- bool mSignalledOutputEos;
- bool mSignalledError;
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftMpeg4Dec);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_MPEG4_DEC_H_
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 9e41d17..9fa9a4c 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -65,8 +65,11 @@
},
include_dirs: ["frameworks/av/media/libstagefright/include"],
- local_include_dirs: ["src"],
- export_include_dirs: ["include"],
+
+ export_include_dirs: [
+ "include",
+ "src",
+ ],
cflags: [
"-DOSCL_UNUSED_ARG(x)=(void)(x)",
@@ -119,50 +122,6 @@
compile_multilib: "32",
}
-cc_library_shared {
- name: "libstagefright_soft_c2mp3dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftMP3.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- local_include_dirs: [
- "src",
- "include",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- static_libs: [
- "libstagefright_mp3dec"
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-}
-
//###############################################################################
cc_test {
name: "libstagefright_mp3dec_test",
diff --git a/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
deleted file mode 100644
index 0a8891e..0000000
--- a/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftMP3"
-#include <utils/Log.h>
-
-#include "pvmp3decoder_api.h"
-
-#include "C2SoftMP3.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-#include <numeric>
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.aac.encoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatAudio)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_MPEG)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-C2SoftMP3::C2SoftMP3(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mConfig(nullptr),
- mDecoderBuf(nullptr) {
-}
-
-C2SoftMP3::~C2SoftMP3() {
- onRelease();
-}
-
-c2_status_t C2SoftMP3::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_NO_MEMORY;
-}
-
-c2_status_t C2SoftMP3::onStop() {
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
- mSignalledError = false;
- mIsFirst = true;
- mSignalledOutputEos = false;
-
- return C2_OK;
-}
-
-void C2SoftMP3::onReset() {
- (void)onStop();
-}
-
-void C2SoftMP3::onRelease() {
- if (mDecoderBuf) {
- free(mDecoderBuf);
- mDecoderBuf = nullptr;
- }
-
- if (mConfig) {
- delete mConfig;
- mConfig = nullptr;
- }
-}
-
-status_t C2SoftMP3::initDecoder() {
- mConfig = new tPVMP3DecoderExternal{};
- if (!mConfig) return NO_MEMORY;
- mConfig->equalizerType = flat;
- mConfig->crcEnabled = false;
-
- size_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
- if (!mDecoderBuf) return NO_MEMORY;
-
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
-
- mNumChannels = 2;
- mSamplingRate = 44100;
- mIsFirst = true;
- mSignalledError = false;
- mSignalledOutputEos = false;
-
- return OK;
-}
-
-/* The below code is borrowed from ./test/mp3reader.cpp */
-static bool parseMp3Header(uint32_t header, size_t *frame_size,
- uint32_t *out_sampling_rate = nullptr,
- uint32_t *out_channels = nullptr,
- uint32_t *out_bitrate = nullptr,
- uint32_t *out_num_samples = nullptr) {
- *frame_size = 0;
- if (out_sampling_rate) *out_sampling_rate = 0;
- if (out_channels) *out_channels = 0;
- if (out_bitrate) *out_bitrate = 0;
- if (out_num_samples) *out_num_samples = 1152;
-
- if ((header & 0xffe00000) != 0xffe00000) return false;
-
- unsigned version = (header >> 19) & 3;
- if (version == 0x01) return false;
-
- unsigned layer = (header >> 17) & 3;
- if (layer == 0x00) return false;
-
- unsigned bitrate_index = (header >> 12) & 0x0f;
- if (bitrate_index == 0 || bitrate_index == 0x0f) return false;
-
- unsigned sampling_rate_index = (header >> 10) & 3;
- if (sampling_rate_index == 3) return false;
-
- static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
- int sampling_rate = kSamplingRateV1[sampling_rate_index];
- if (version == 2 /* V2 */) {
- sampling_rate /= 2;
- } else if (version == 0 /* V2.5 */) {
- sampling_rate /= 4;
- }
-
- unsigned padding = (header >> 9) & 1;
-
- if (layer == 3) { // layer I
- static const int kBitrateV1[] =
- {
- 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
- };
- static const int kBitrateV2[] =
- {
- 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256
- };
-
- int bitrate = (version == 3 /* V1 */) ? kBitrateV1[bitrate_index - 1] :
- kBitrateV2[bitrate_index - 1];
-
- if (out_bitrate) {
- *out_bitrate = bitrate;
- }
- *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
- if (out_num_samples) {
- *out_num_samples = 384;
- }
- } else { // layer II or III
- static const int kBitrateV1L2[] =
- {
- 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
- };
-
- static const int kBitrateV1L3[] =
- {
- 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
- };
-
- static const int kBitrateV2[] =
- {
- 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
- };
-
- int bitrate;
- if (version == 3 /* V1 */) {
- bitrate = (layer == 2 /* L2 */) ? kBitrateV1L2[bitrate_index - 1] :
- kBitrateV1L3[bitrate_index - 1];
-
- if (out_num_samples) {
- *out_num_samples = 1152;
- }
- } else { // V2 (or 2.5)
- bitrate = kBitrateV2[bitrate_index - 1];
- if (out_num_samples) {
- *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
- }
- }
-
- if (out_bitrate) {
- *out_bitrate = bitrate;
- }
-
- if (version == 3 /* V1 */) {
- *frame_size = 144000 * bitrate / sampling_rate + padding;
- } else { // V2 or V2.5
- size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
- *frame_size = tmp * bitrate / sampling_rate + padding;
- }
- }
-
- if (out_sampling_rate) {
- *out_sampling_rate = sampling_rate;
- }
-
- if (out_channels) {
- int channel_mode = (header >> 6) & 3;
-
- *out_channels = (channel_mode == 3) ? 1 : 2;
- }
-
- return true;
-}
-
-static uint32_t U32_AT(const uint8_t *ptr) {
- return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
-}
-
-static status_t calculateOutSize(uint8 *header, size_t inSize,
- std::vector<size_t> *decodedSizes) {
- uint32_t channels;
- uint32_t numSamples;
- size_t frameSize;
- size_t totalInSize = 0;
-
- while (totalInSize + 4 < inSize) {
- if (!parseMp3Header(U32_AT(header + totalInSize), &frameSize,
- nullptr, &channels, nullptr, &numSamples)) {
- ALOGE("Error in parse mp3 header during outSize estimation");
- return UNKNOWN_ERROR;
- }
- totalInSize += frameSize;
- decodedSizes->push_back(numSamples * channels * sizeof(int16_t));
- }
-
- if (decodedSizes->empty()) return UNKNOWN_ERROR;
-
- return OK;
-}
-
-c2_status_t C2SoftMP3::onFlush_sm() {
- return onStop();
-}
-
-c2_status_t C2SoftMP3::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- return C2_OK;
-}
-
-// TODO: Can overall error checking be improved? As in the check for validity of
-// work, pool ptr, work->input.buffers.size() == 1, ...
-// TODO: Gapless playback: decoder has a delay of 529 samples. For the first
-// frame we intend to remove 529 samples worth of data. When this is
-// done it is going to effect the timestamps of future frames. This
-// timestamp correction is handled by the client or plugin? Soft omx mp3
-// plugin also has this problem
-// TODO: Blind removal of 529 samples from the output may not work. Because
-// mpeg layer 1 frame size is 384 samples per frame. This should introduce
-// negative values and can cause SEG faults. Soft omx mp3 plugin can have
-// this problem (CHECK!)
-void C2SoftMP3::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = inBuffer.map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- if (inSize == 0) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- return;
- }
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
- (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
-
- size_t calOutSize;
- std::vector<size_t> decodedSizes;
- if (OK != calculateOutSize(const_cast<uint8 *>(rView.data() + inOffset),
- inSize, &decodedSizes)) {
- work->result = C2_CORRUPTED;
- return;
- }
- calOutSize = std::accumulate(decodedSizes.begin(), decodedSizes.end(), 0);
- std::shared_ptr<C2LinearBlock> block;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(calOutSize, usage, &block);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = block->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- int outSize = 0;
- int outOffset = 0;
- auto it = decodedSizes.begin();
- while (inOffset < inSize) {
- if (it == decodedSizes.end()) {
- ALOGE("unexpected trailing bytes, ignoring them");
- break;
- }
-
- mConfig->pInputBuffer = const_cast<uint8 *>(rView.data() + inOffset);
- mConfig->inputBufferCurrentLength = (inSize - inOffset);
- mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
- mConfig->outputFrameSize = (calOutSize - outSize);
- mConfig->pOutputBuffer = reinterpret_cast<int16_t *> (wView.data() + outSize);
-
- ERROR_CODE decoderErr;
- if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
- != NO_DECODING_ERROR) {
- ALOGE("mp3 decoder returned error %d", decoderErr);
- if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
- && decoderErr != SIDE_INFO_ERROR) {
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
-
- // This is recoverable, just ignore the current frame and
- // play silence instead.
- ALOGV("ignoring error and sending silence");
- if (mConfig->outputFrameSize == 0) {
- mConfig->outputFrameSize = *it / sizeof(int16_t);
- }
- memset(mConfig->pOutputBuffer, 0, mConfig->outputFrameSize * sizeof(int16_t));
- } else if (mConfig->samplingRate != mSamplingRate
- || mConfig->num_channels != mNumChannels) {
- mSamplingRate = mConfig->samplingRate;
- mNumChannels = mConfig->num_channels;
- }
- if (*it != mConfig->outputFrameSize * sizeof(int16_t)) {
- ALOGE("panic, parsed size does not match decoded size");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- outSize += mConfig->outputFrameSize * sizeof(int16_t);
- inOffset += mConfig->inputBufferUsedLength;
- it++;
- }
- if (mIsFirst) {
- mIsFirst = false;
- // The decoder delay is 529 samples, so trim that many samples off
- // the start of the first output buffer. This essentially makes this
- // decoder have zero delay, which the rest of the pipeline assumes.
- outOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
- }
- ALOGV("out buffer attr. offset %d size %d", outOffset, outSize);
- decodedSizes.clear();
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, outOffset, outSize));
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
-}
-
-class C2SoftMp3DecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftMP3(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftMp3DecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftMp3DecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
-
diff --git a/media/libstagefright/codecs/mp3dec/C2SoftMP3.h b/media/libstagefright/codecs/mp3dec/C2SoftMP3.h
deleted file mode 100644
index ad974bd..0000000
--- a/media/libstagefright/codecs/mp3dec/C2SoftMP3.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_MP3_H_
-#define C2_SOFT_MP3_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-struct tPVMP3DecoderExternal;
-
-bool parseMp3Header(uint32_t header, size_t *frame_size,
- uint32_t *out_sampling_rate = nullptr,
- uint32_t *out_channels = nullptr,
- uint32_t *out_bitrate = nullptr,
- uint32_t *out_num_samples = nullptr);
-
-namespace android {
-
-struct C2SoftMP3 : public SimpleC2Component {
- C2SoftMP3(const char *name, c2_node_id_t id);
- virtual ~C2SoftMP3();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-
-private:
- enum {
- kPVMP3DecoderDelay = 529 // samples
- };
-
- tPVMP3DecoderExternal *mConfig;
- void *mDecoderBuf;
-
- int32_t mNumChannels;
- int32_t mSamplingRate;
- bool mIsFirst;
- bool mSignalledError;
- bool mSignalledOutputEos;
-
- status_t initDecoder();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftMP3);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_MP3_H_
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 3123376..fb0db8f 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -1,47 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2mpeg2dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftMpeg2Dec.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- include_dirs: [
- "external/libmpeg2/decoder",
- "external/libmpeg2/common",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: false, // true,
- diag: {
- cfi: false, // true,
- },
- },
-
- static_libs: ["libmpeg2dec"],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-cc_library_shared {
name: "libstagefright_soft_mpeg2dec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.cpp b/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.cpp
deleted file mode 100644
index 74ea340..0000000
--- a/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.cpp
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftMpeg2Dec"
-#include <utils/Log.h>
-
-#include "iv_datatypedef.h"
-#include "iv.h"
-#include "ivd.h"
-#include "impeg2d.h"
-#include "C2SoftMpeg2Dec.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.mpeg2.decoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatVideo)
- .inputMediaType(MEDIA_MIMETYPE_VIDEO_MPEG2)
- .outputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
- .build();
-}
-
-static size_t getCpuCoreCount() {
- long cpuCoreCount = 1;
-#if defined(_SC_NPROCESSORS_ONLN)
- cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
- // _SC_NPROC_ONLN must be defined...
- cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
- CHECK(cpuCoreCount >= 1);
- ALOGV("Number of CPU cores: %ld", cpuCoreCount);
- return (size_t)cpuCoreCount;
-}
-
-static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) {
- return memalign(alignment, size);
-}
-
-static void ivd_aligned_free(void *mem) {
- free(mem);
-}
-
-C2SoftMpeg2Dec::C2SoftMpeg2Dec(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mDecHandle(nullptr),
- mMemRecords(nullptr),
- mOutBufferDrain(nullptr),
- mIvColorformat(IV_YUV_420P),
- mWidth(320),
- mHeight(240) {
- // If input dump is enabled, then open create an empty file
- GENERATE_FILE_NAMES();
- CREATE_DUMP_FILE(mInFile);
-}
-
-C2SoftMpeg2Dec::~C2SoftMpeg2Dec() {
- onRelease();
-}
-
-c2_status_t C2SoftMpeg2Dec::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-c2_status_t C2SoftMpeg2Dec::onStop() {
- if (OK != resetDecoder()) return C2_CORRUPTED;
- resetPlugin();
- return C2_OK;
-}
-
-void C2SoftMpeg2Dec::onReset() {
- (void) onStop();
-}
-
-void C2SoftMpeg2Dec::onRelease() {
- (void) deleteDecoder();
- if (mOutBufferDrain) {
- ivd_aligned_free(mOutBufferDrain);
- mOutBufferDrain = nullptr;
- }
- if (mOutBlock) {
- mOutBlock.reset();
- }
- if (mMemRecords) {
- ivd_aligned_free(mMemRecords);
- mMemRecords = nullptr;
- }
-}
-
-c2_status_t C2SoftMpeg2Dec::onFlush_sm() {
- if (OK != setFlushMode()) return C2_CORRUPTED;
-
- uint32_t displayStride = mStride;
- uint32_t displayHeight = mHeight;
- uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
- mOutBufferDrain = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
- if (!mOutBufferDrain) {
- ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
- return C2_NO_MEMORY;
- }
-
- while (true) {
- ivd_video_decode_ip_t s_decode_ip;
- ivd_video_decode_op_t s_decode_op;
-
- setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
- (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
- if (0 == s_decode_op.u4_output_present) {
- resetPlugin();
- break;
- }
- }
-
- ivd_aligned_free(mOutBufferDrain);
- mOutBufferDrain = nullptr;
-
- return C2_OK;
-}
-
-status_t C2SoftMpeg2Dec::getNumMemRecords() {
- iv_num_mem_rec_ip_t s_num_mem_rec_ip;
- iv_num_mem_rec_op_t s_num_mem_rec_op;
-
- s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
- s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
- s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
-
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_num_mem_rec_ip,
- &s_num_mem_rec_op);
- if (IV_SUCCESS != status) {
- ALOGE("Error in getting mem records: 0x%x", s_num_mem_rec_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
- mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::fillMemRecords() {
- iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *) ivd_aligned_malloc(
- 128, mNumMemRecords * sizeof(iv_mem_rec_t));
- if (!ps_mem_rec) {
- ALOGE("Allocation failure");
- return NO_MEMORY;
- }
- memset(ps_mem_rec, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
- for (size_t i = 0; i < mNumMemRecords; i++)
- ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
- mMemRecords = ps_mem_rec;
-
- ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
- ivdext_fill_mem_rec_op_t s_fill_mem_op;
-
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
- s_fill_mem_ip.u4_share_disp_buf = 0;
- s_fill_mem_ip.e_output_format = mIvColorformat;
- s_fill_mem_ip.u4_deinterlace = 1;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
- s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_fill_mem_ip,
- &s_fill_mem_op);
- if (IV_SUCCESS != status) {
- ALOGE("Error in filling mem records: 0x%x",
- s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- CHECK_EQ(mNumMemRecords, s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled);
- for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
- ps_mem_rec->pv_base = ivd_aligned_malloc(
- ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
- if (!ps_mem_rec->pv_base) {
- ALOGE("Allocation failure for memory record #%zu of size %u",
- i, ps_mem_rec->u4_mem_size);
- return NO_MEMORY;
- }
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::createDecoder() {
- ivdext_init_ip_t s_init_ip;
- ivdext_init_op_t s_init_op;
-
- s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
- s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
- s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
- s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
- s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
- s_init_ip.u4_share_disp_buf = 0;
- s_init_ip.u4_deinterlace = 1;
- s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
- s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
- s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
-
- mDecHandle = (iv_obj_t *)mMemRecords[0].pv_base;
- mDecHandle->pv_fxns = (void *)ivdec_api_function;
- mDecHandle->u4_size = sizeof(iv_obj_t);
-
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_init_ip,
- &s_init_op);
- if (status != IV_SUCCESS) {
- ALOGE("error in %s: 0x%x", __func__,
- s_init_op.s_ivd_init_op_t.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::setNumCores() {
- ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
- ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
-
- s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
- s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
- s_set_num_cores_ip.u4_num_cores = mNumCores;
- s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_set_num_cores_ip,
- &s_set_num_cores_op);
- if (status != IV_SUCCESS) {
- ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::setParams(size_t stride) {
- ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
- ivd_ctl_set_config_op_t s_set_dyn_params_op;
-
- s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
- s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
- s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
- s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
- s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
- s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
- s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_set_dyn_params_ip,
- &s_set_dyn_params_op);
- if (status != IV_SUCCESS) {
- ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::getVersion() {
- ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
- ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
- UWORD8 au1_buf[512];
-
- s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
- s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
- s_get_versioninfo_ip.pv_version_buffer = au1_buf;
- s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
- s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_get_versioninfo_ip,
- &s_get_versioninfo_op);
- if (status != IV_SUCCESS) {
- ALOGD("error in %s: 0x%x", __func__,
- s_get_versioninfo_op.u4_error_code);
- } else {
- ALOGV("ittiam decoder version number: %s",
- (char *) s_get_versioninfo_ip.pv_version_buffer);
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::initDecoder() {
- status_t ret = getNumMemRecords();
- if (OK != ret) return ret;
-
- ret = fillMemRecords();
- if (OK != ret) return ret;
-
- if (OK != createDecoder()) return UNKNOWN_ERROR;
-
- mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
- mStride = ALIGN64(mWidth);
- mSignalledError = false;
- mPreference = kPreferBitstream;
- memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
- memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
- memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
- mUpdateColorAspects = false;
- resetPlugin();
- (void) setNumCores();
- if (OK != setParams(mStride)) return UNKNOWN_ERROR;
- (void) getVersion();
-
- return OK;
-}
-
-bool C2SoftMpeg2Dec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
- ivd_video_decode_op_t *ps_decode_op,
- C2ReadView *inBuffer,
- C2GraphicView *outBuffer,
- size_t inOffset,
- size_t inSize,
- uint32_t tsMarker) {
- uint32_t displayStride = mStride;
- uint32_t displayHeight = mHeight;
- size_t lumaSize = displayStride * displayHeight;
- size_t chromaSize = lumaSize >> 2;
-
- ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
- ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
- if (inBuffer) {
- ps_decode_ip->u4_ts = tsMarker;
- ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
- ps_decode_ip->u4_num_Bytes = inSize - inOffset;
- } else {
- ps_decode_ip->u4_ts = 0;
- ps_decode_ip->pv_stream_buffer = nullptr;
- ps_decode_ip->u4_num_Bytes = 0;
- }
- ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
- ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
- ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
- if (outBuffer) {
- if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
- ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
- outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
- return false;
- }
- ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
- ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
- ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
- } else {
- ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferDrain;
- ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferDrain + lumaSize;
- ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferDrain + lumaSize + chromaSize;
- }
- ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
- ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t);
-
- return true;
-}
-
-bool C2SoftMpeg2Dec::colorAspectsDiffer(
- const ColorAspects &a, const ColorAspects &b) {
- if (a.mRange != b.mRange
- || a.mPrimaries != b.mPrimaries
- || a.mTransfer != b.mTransfer
- || a.mMatrixCoeffs != b.mMatrixCoeffs) {
- return true;
- }
- return false;
-}
-
-void C2SoftMpeg2Dec::updateFinalColorAspects(
- const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
- Mutex::Autolock autoLock(mColorAspectsLock);
- ColorAspects newAspects;
- newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
- preferredAspects.mRange : otherAspects.mRange;
- newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
- preferredAspects.mPrimaries : otherAspects.mPrimaries;
- newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
- preferredAspects.mTransfer : otherAspects.mTransfer;
- newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
- preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
-
- // Check to see if need update mFinalColorAspects.
- if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
- mFinalColorAspects = newAspects;
- mUpdateColorAspects = true;
- }
-}
-
-status_t C2SoftMpeg2Dec::handleColorAspectsChange() {
- if (mPreference == kPreferBitstream) {
- updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
- } else if (mPreference == kPreferContainer) {
- updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
- } else {
- return C2_CORRUPTED;
- }
- return C2_OK;
-}
-
-bool C2SoftMpeg2Dec::getSeqInfo() {
- ivdext_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
- ivdext_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
-
- s_ctl_get_seq_info_ip.u4_size = sizeof(ivdext_ctl_get_seq_info_ip_t);
- s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_ctl_get_seq_info_ip.e_sub_cmd =
- (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
- s_ctl_get_seq_info_op.u4_size = sizeof(ivdext_ctl_get_seq_info_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_ctl_get_seq_info_ip,
- &s_ctl_get_seq_info_op);
- if (status != IV_SUCCESS) {
- ALOGW("Error in getting Sequence info: 0x%x", s_ctl_get_seq_info_op.u4_error_code);
- return false;
- }
-
- int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
- int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
- int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
- bool full_range = false; // mpeg2 video has limited range.
-
- ColorAspects colorAspects;
- ColorUtils::convertIsoColorAspectsToCodecAspects(
- primaries, transfer, coeffs, full_range, colorAspects);
- // Update color aspects if necessary.
- if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
- mBitstreamColorAspects = colorAspects;
- status_t err = handleColorAspectsChange();
- CHECK(err == OK);
- }
-
- return true;
-}
-
-status_t C2SoftMpeg2Dec::setFlushMode() {
- ivd_ctl_flush_ip_t s_set_flush_ip;
- ivd_ctl_flush_op_t s_set_flush_op;
-
- s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
- s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
- s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_set_flush_ip,
- &s_set_flush_op);
- if (status != IV_SUCCESS) {
- ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::resetDecoder() {
- ivd_ctl_reset_ip_t s_reset_ip;
- ivd_ctl_reset_op_t s_reset_op;
-
- s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
- s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
- s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
- s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
- IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
- &s_reset_ip,
- &s_reset_op);
- if (IV_SUCCESS != status) {
- ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
- (void) setNumCores();
- mStride = 0;
- mSignalledError = false;
-
- return OK;
-}
-
-void C2SoftMpeg2Dec::resetPlugin() {
- mSignalledOutputEos = false;
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
-}
-
-status_t C2SoftMpeg2Dec::deleteDecoder() {
- if (mMemRecords) {
- iv_mem_rec_t *ps_mem_rec = mMemRecords;
-
- for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
- if (ps_mem_rec->pv_base) {
- ivd_aligned_free(ps_mem_rec->pv_base);
- }
- }
- ivd_aligned_free(mMemRecords);
- mMemRecords = nullptr;
- }
- mDecHandle = nullptr;
-
- return OK;
-}
-
-status_t C2SoftMpeg2Dec::reInitDecoder() {
- deleteDecoder();
-
- status_t ret = initDecoder();
- if (OK != ret) {
- ALOGE("Failed to initialize decoder");
- deleteDecoder();
- return ret;
- }
- return OK;
-}
-
-void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-void C2SoftMpeg2Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
- std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
- C2Rect(mWidth, mHeight));
- mOutBlock = nullptr;
- auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
- (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
- fillWork(work);
- } else {
- finish(index, fillWork);
- }
-}
-
-c2_status_t C2SoftMpeg2Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
- if (!mDecHandle) {
- ALOGE("not supposed to be here, invalid decoder context");
- return C2_CORRUPTED;
- }
- if (mStride != ALIGN64(mWidth)) {
- mStride = ALIGN64(mWidth);
- if (OK != setParams(mStride)) return C2_CORRUPTED;
- }
- if (mOutBlock &&
- (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
- mOutBlock.reset();
- }
- if (!mOutBlock) {
- uint32_t format = HAL_PIXEL_FORMAT_YV12;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
- if (err != C2_OK) {
- ALOGE("fetchGraphicBlock for Output failed with status %d", err);
- return err;
- }
- ALOGV("provided (%dx%d) required (%dx%d)",
- mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
- }
-
- return C2_OK;
-}
-
-// TODO: can overall error checking be improved?
-// TODO: allow configuration of color format and usage for graphic buffers instead
-// of hard coding them to HAL_PIXEL_FORMAT_YV12
-// TODO: pass coloraspects information to surface
-// TODO: test support for dynamic change in resolution
-// TODO: verify if the decoder sent back all frames
-void C2SoftMpeg2Dec::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- bool hasPicture = false;
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
- inSize, (int)work->input.ordinal.timestamp.peeku(),
- (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
- while (inOffset < inSize) {
- if (C2_OK != ensureDecoderState(pool)) {
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- C2GraphicView wView = mOutBlock->map().get();
- if (wView.error()) {
- ALOGE("graphic view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- ivd_video_decode_ip_t s_decode_ip;
- ivd_video_decode_op_t s_decode_op;
- if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
- inOffset, inSize, workIndex)) {
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- // If input dump is enabled, then write to file
- DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
- WORD32 delay;
- GETTIME(&mTimeStart, NULL);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
- (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
- WORD32 decodeTime;
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%6d delay=%6d numBytes=%6d ", decodeTime, delay,
- s_decode_op.u4_num_bytes_consumed);
- if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) {
- ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
- drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
- resetPlugin();
- mWidth = s_decode_op.u4_pic_wd;
- mHeight = s_decode_op.u4_pic_ht;
- if (OK != reInitDecoder()) {
- ALOGE("Failed to reinitialize decoder");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- continue;
- } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
- ALOGV("resolution changed");
- drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
- resetDecoder();
- resetPlugin();
- mWidth = s_decode_op.u4_pic_wd;
- mHeight = s_decode_op.u4_pic_ht;
- continue;
- }
-
- (void) getSeqInfo();
- if (mUpdateColorAspects) {
- mUpdateColorAspects = false;
- }
- hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
- if (s_decode_op.u4_output_present) {
- finishWork(s_decode_op.u4_ts, work);
- }
- inOffset += s_decode_op.u4_num_bytes_consumed;
- if (hasPicture && (inSize - inOffset)) {
- ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
- (int)inSize - (int)inOffset);
- break;
- }
- }
-
- if (eos) {
- drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
- mSignalledOutputEos = true;
- } else if (!hasPicture) {
- fillEmptyWork(work);
- }
-}
-
-c2_status_t C2SoftMpeg2Dec::drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work) {
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- if (OK != setFlushMode()) return C2_CORRUPTED;
- while (true) {
- if (C2_OK != ensureDecoderState(pool)) {
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return C2_CORRUPTED;
- }
- C2GraphicView wView = mOutBlock->map().get();
- if (wView.error()) {
- ALOGE("graphic view map failed %d", wView.error());
- return C2_CORRUPTED;
- }
- ivd_video_decode_ip_t s_decode_ip;
- ivd_video_decode_op_t s_decode_op;
- if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
- mSignalledError = true;
- return C2_CORRUPTED;
- }
- (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
- if (s_decode_op.u4_output_present) {
- finishWork(s_decode_op.u4_ts, work);
- } else {
- break;
- }
- }
- if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
- work && work->workletsProcessed == 0u) {
- fillEmptyWork(work);
- }
-
- return C2_OK;
-}
-
-c2_status_t C2SoftMpeg2Dec::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- return drainInternal(drainMode, pool, nullptr);
-}
-
-class C2SoftMpeg2DecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftMpeg2Dec(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftMpeg2DecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftMpeg2DecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.h b/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.h
deleted file mode 100644
index 64e5b05..0000000
--- a/media/libstagefright/codecs/mpeg2dec/C2SoftMpeg2Dec.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_MPEG2_DEC_H_
-#define C2_SOFT_MPEG2_DEC_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/ColorUtils.h>
-
-namespace android {
-
-#define ivdec_api_function impeg2d_api_function
-#define ivdext_init_ip_t impeg2d_init_ip_t
-#define ivdext_init_op_t impeg2d_init_op_t
-#define ivdext_fill_mem_rec_ip_t impeg2d_fill_mem_rec_ip_t
-#define ivdext_fill_mem_rec_op_t impeg2d_fill_mem_rec_op_t
-#define ivdext_ctl_set_num_cores_ip_t impeg2d_ctl_set_num_cores_ip_t
-#define ivdext_ctl_set_num_cores_op_t impeg2d_ctl_set_num_cores_op_t
-#define ivdext_ctl_get_seq_info_ip_t impeg2d_ctl_get_seq_info_ip_t
-#define ivdext_ctl_get_seq_info_op_t impeg2d_ctl_get_seq_info_op_t
-#define ALIGN64(x) ((((x) + 63) >> 6) << 6)
-#define MAX_NUM_CORES 4
-#define IVDEXT_CMD_CTL_SET_NUM_CORES \
- (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
-#ifdef FILE_DUMP_ENABLE
- #define INPUT_DUMP_PATH "/sdcard/clips/mpeg2d_input"
- #define INPUT_DUMP_EXT "m2v"
- #define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
- INPUT_DUMP_EXT); \
- }
- #define CREATE_DUMP_FILE(m_filename) { \
- FILE *fp = fopen(m_filename, "wb"); \
- if (fp != NULL) { \
- fclose(fp); \
- } else { \
- ALOGD("Could not open file %s", m_filename); \
- } \
- }
- #define DUMP_TO_FILE(m_filename, m_buf, m_size) \
- { \
- FILE *fp = fopen(m_filename, "ab"); \
- if (fp != NULL && m_buf != NULL) { \
- uint32_t i; \
- i = fwrite(m_buf, 1, m_size, fp); \
- ALOGD("fwrite ret %d to write %d", i, m_size); \
- if (i != (uint32_t)m_size) { \
- ALOGD("Error in fwrite, returned %d", i); \
- perror("Error in write to file"); \
- } \
- fclose(fp); \
- } else { \
- ALOGD("Could not write to file %s", m_filename);\
- } \
- }
-#else /* FILE_DUMP_ENABLE */
- #define INPUT_DUMP_PATH
- #define INPUT_DUMP_EXT
- #define OUTPUT_DUMP_PATH
- #define OUTPUT_DUMP_EXT
- #define GENERATE_FILE_NAMES()
- #define CREATE_DUMP_FILE(m_filename)
- #define DUMP_TO_FILE(m_filename, m_buf, m_size)
-#endif /* FILE_DUMP_ENABLE */
-
-struct C2SoftMpeg2Dec : public SimpleC2Component {
- C2SoftMpeg2Dec(const char *name, c2_node_id_t id);
- virtual ~C2SoftMpeg2Dec();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
- private:
- status_t getNumMemRecords();
- status_t fillMemRecords();
- status_t createDecoder();
- status_t setNumCores();
- status_t setParams(size_t stride);
- status_t getVersion();
- status_t initDecoder();
- bool setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
- ivd_video_decode_op_t *ps_decode_op,
- C2ReadView *inBuffer,
- C2GraphicView *outBuffer,
- size_t inOffset,
- size_t inSize,
- uint32_t tsMarker);
- bool getSeqInfo();
- // TODO:This is not the right place for colorAspects functions. These should
- // be part of c2-vndk so that they can be accessed by all video plugins
- // until then, make them feel at home
- bool colorAspectsDiffer(const ColorAspects &a, const ColorAspects &b);
- void updateFinalColorAspects(
- const ColorAspects &otherAspects, const ColorAspects &preferredAspects);
- status_t handleColorAspectsChange();
- c2_status_t ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool);
- void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work);
- status_t setFlushMode();
- c2_status_t drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work);
- status_t resetDecoder();
- void resetPlugin();
- status_t deleteDecoder();
- status_t reInitDecoder();
-
- // TODO:This is not the right place for this enum. These should
- // be part of c2-vndk so that they can be accessed by all video plugins
- // until then, make them feel at home
- enum {
- kNotSupported,
- kPreferBitstream,
- kPreferContainer,
- };
-
- iv_obj_t *mDecHandle;
- iv_mem_rec_t *mMemRecords;
- size_t mNumMemRecords;
- std::shared_ptr<C2GraphicBlock> mOutBlock;
- uint8_t *mOutBufferDrain;
-
- size_t mNumCores;
- IV_COLOR_FORMAT_T mIvColorformat;
-
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mStride;
- bool mSignalledOutputEos;
- bool mSignalledError;
-
- // ColorAspects
- Mutex mColorAspectsLock;
- int mPreference;
- ColorAspects mDefaultColorAspects;
- ColorAspects mBitstreamColorAspects;
- ColorAspects mFinalColorAspects;
- bool mUpdateColorAspects;
-
- // profile
- struct timeval mTimeStart;
- struct timeval mTimeEnd;
-#ifdef FILE_DUMP_ENABLE
- char mInFile[200];
-#endif /* FILE_DUMP_ENABLE */
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftMpeg2Dec);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_MPEG2_DEC_H_
diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp
index 03f0c05..8a9399a 100644
--- a/media/libstagefright/codecs/on2/dec/Android.bp
+++ b/media/libstagefright/codecs/on2/dec/Android.bp
@@ -37,82 +37,3 @@
},
compile_multilib: "32",
}
-
-cc_library_shared {
- name: "libstagefright_soft_c2vp9dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftVpx.cpp"],
-
- static_libs: ["libvpx"],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- cflags: [
- "-DVP9",
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
-
-cc_library_shared {
- name: "libstagefright_soft_c2vp8dec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftVpx.cpp"],
-
- static_libs: ["libvpx"],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- ldflags: ["-Wl,-Bsymbolic"],
-}
diff --git a/media/libstagefright/codecs/on2/dec/C2SoftVpx.cpp b/media/libstagefright/codecs/on2/dec/C2SoftVpx.cpp
deleted file mode 100644
index 8528f26..0000000
--- a/media/libstagefright/codecs/on2/dec/C2SoftVpx.cpp
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftVpx"
-#include <utils/Log.h>
-
-#include "C2SoftVpx.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-namespace android {
-
-#ifdef VP9
-constexpr char kComponentName[] = "c2.google.vp9.decoder";
-#else
-constexpr char kComponentName[] = "c2.google.vp8.decoder";
-#endif
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatVideo)
- .inputMediaType(
-#ifdef VP9
- MEDIA_MIMETYPE_VIDEO_VP9
-#else
- MEDIA_MIMETYPE_VIDEO_VP8
-#endif
- )
- .outputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
- .build();
-}
-
-C2SoftVpx::C2SoftVpx(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mCodecCtx(nullptr) {
-}
-
-C2SoftVpx::~C2SoftVpx() {
- onRelease();
-}
-
-c2_status_t C2SoftVpx::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_CORRUPTED;
-}
-
-c2_status_t C2SoftVpx::onStop() {
- (void) onFlush_sm();
- destroyDecoder();
-
- mSignalledError = false;
- mSignalledOutputEos = false;
-
- return C2_OK;
-}
-
-void C2SoftVpx::onReset() {
- (void) onStop();
- (void) initDecoder();
-}
-
-void C2SoftVpx::onRelease() {
- destroyDecoder();
-}
-
-c2_status_t C2SoftVpx::onFlush_sm() {
- if (mFrameParallelMode) {
- // Flush decoder by passing nullptr data ptr and 0 size.
- // Ideally, this should never fail.
- if (vpx_codec_decode(mCodecCtx, nullptr, 0, nullptr, 0)) {
- ALOGE("Failed to flush on2 decoder.");
- return C2_CORRUPTED;
- }
- }
-
- // Drop all the decoded frames in decoder.
- vpx_codec_iter_t iter = nullptr;
- while (vpx_codec_get_frame(mCodecCtx, &iter)) {
- }
-
- mSignalledError = false;
- mSignalledOutputEos = false;
- return C2_OK;
-}
-
-static int GetCPUCoreCount() {
- int cpuCoreCount = 1;
-#if defined(_SC_NPROCESSORS_ONLN)
- cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
- // _SC_NPROC_ONLN must be defined...
- cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
- CHECK(cpuCoreCount >= 1);
- ALOGV("Number of CPU cores: %d", cpuCoreCount);
- return cpuCoreCount;
-}
-
-status_t C2SoftVpx::initDecoder() {
-#ifdef VP9
- mMode = MODE_VP9;
-#else
- mMode = MODE_VP8;
-#endif
-
- mWidth = 320;
- mHeight = 240;
- mFrameParallelMode = false;
- mSignalledOutputEos = false;
- mSignalledError = false;
-
- mCodecCtx = new vpx_codec_ctx_t;
-
- vpx_codec_dec_cfg_t cfg;
- memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
- cfg.threads = GetCPUCoreCount();
-
- vpx_codec_flags_t flags;
- memset(&flags, 0, sizeof(vpx_codec_flags_t));
- if (mFrameParallelMode) flags |= VPX_CODEC_USE_FRAME_THREADING;
-
- vpx_codec_err_t vpx_err;
- if ((vpx_err = vpx_codec_dec_init(
- mCodecCtx, mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
- &cfg, flags))) {
- ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t C2SoftVpx::destroyDecoder() {
- if (mCodecCtx) {
- vpx_codec_destroy(mCodecCtx);
- delete mCodecCtx;
- mCodecCtx = nullptr;
- }
-
- return OK;
-}
-
-void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-void C2SoftVpx::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2GraphicBlock> &block) {
- std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
- C2Rect(mWidth, mHeight));
- auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
- uint32_t flags = 0;
- if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
- (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
- flags |= C2FrameData::FLAG_END_OF_STREAM;
- ALOGV("signalling eos");
- }
- work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(buffer);
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- };
- if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
- fillWork(work);
- } else {
- finish(index, fillWork);
- }
-}
-
-void C2SoftVpx::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) !=0);
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
- inSize, (int)work->input.ordinal.timestamp.peeku(),
- (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
-
- // Software VP9 Decoder does not need the Codec Specific Data (CSD)
- // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
- // it was passed.
- if (codecConfig) {
- // Ignore CSD buffer for VP9.
- if (mMode == MODE_VP9) {
- fillEmptyWork(work);
- return;
- } else {
- // Tolerate the CSD buffer for VP8. This is a workaround
- // for b/28689536. continue
- ALOGW("WARNING: Got CSD buffer for VP8. Continue");
- }
- }
-
- uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
- int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
-
- if (inSize) {
- vpx_codec_err_t err = vpx_codec_decode(
- mCodecCtx, bitstream, inSize, &frameIndex, 0);
- if (err != VPX_CODEC_OK) {
- ALOGE("on2 decoder failed to decode frame. err: %d", err);
- work->result = C2_CORRUPTED;
- mSignalledError = true;
- return;
- }
- }
-
- (void)outputBuffer(pool, work);
-
- if (eos) {
- drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
- mSignalledOutputEos = true;
- } else if (!inSize) {
- fillEmptyWork(work);
- }
-}
-
-static void copyOutputBufferToYV12Frame(uint8_t *dst,
- const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- uint32_t width, uint32_t height, int32_t bpp) {
- size_t dstYStride = align(width, 16) * bpp ;
- size_t dstUVStride = align(dstYStride / 2, 16);
- uint8_t *dstStart = dst;
-
- for (size_t i = 0; i < height; ++i) {
- memcpy(dst, srcY, width * bpp);
- srcY += srcYStride;
- dst += dstYStride;
- }
-
- dst = dstStart + dstYStride * height;
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dst, srcV, width / 2 * bpp);
- srcV += srcVStride;
- dst += dstUVStride;
- }
-
- dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dst, srcU, width / 2 * bpp);
- srcU += srcUStride;
- dst += dstUVStride;
- }
-}
-
-bool C2SoftVpx::outputBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work)
-{
- if (!(work && pool)) return false;
-
- vpx_codec_iter_t iter = nullptr;
- vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
-
- if (!img) return false;
-
- mWidth = img->d_w;
- mHeight = img->d_h;
-
- CHECK(img->fmt == VPX_IMG_FMT_I420 || img->fmt == VPX_IMG_FMT_I42016);
- int32_t bpp = 1;
- if (img->fmt == VPX_IMG_FMT_I42016) {
- bpp = 2;
- }
-
- std::shared_ptr<C2GraphicBlock> block;
- uint32_t format = HAL_PIXEL_FORMAT_YV12;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16) * bpp, mHeight, format, usage, &block);
- if (err != C2_OK) {
- ALOGE("fetchGraphicBlock for Output failed with status %d", err);
- work->result = err;
- return false;
- }
-
- C2GraphicView wView = block->map().get();
- if (wView.error()) {
- ALOGE("graphic view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return false;
- }
-
- ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
- block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
-
- uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
- size_t srcYStride = img->stride[VPX_PLANE_Y];
- size_t srcUStride = img->stride[VPX_PLANE_U];
- size_t srcVStride = img->stride[VPX_PLANE_V];
- const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
- const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
- const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
- copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride, mWidth, mHeight, bpp);
-
- finishWork(*(int64_t *)img->user_priv, work, std::move(block));
- return true;
-}
-
-c2_status_t C2SoftVpx::drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work) {
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- while ((outputBuffer(pool, work))) {
- }
-
- if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
- work && work->workletsProcessed == 0u) {
- fillEmptyWork(work);
- }
-
- return C2_OK;
-}
-c2_status_t C2SoftVpx::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- return drainInternal(drainMode, pool, nullptr);
-}
-
-class C2SoftVpxFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftVpx(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftVpxFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftVpxFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/on2/dec/C2SoftVpx.h b/media/libstagefright/codecs/on2/dec/C2SoftVpx.h
deleted file mode 100644
index b5d4e21..0000000
--- a/media/libstagefright/codecs/on2/dec/C2SoftVpx.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_VPX_H_
-#define C2_SOFT_VPX_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-#include "vpx/vpx_decoder.h"
-#include "vpx/vp8dx.h"
-
-namespace android {
-
-struct C2SoftVpx : public SimpleC2Component {
- C2SoftVpx(const char *name, c2_node_id_t id);
- virtual ~C2SoftVpx();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
- private:
- enum {
- MODE_VP8,
- MODE_VP9,
- } mMode;
-
- vpx_codec_ctx_t *mCodecCtx;
- bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder.
-
- uint32_t mWidth;
- uint32_t mHeight;
- bool mSignalledOutputEos;
- bool mSignalledError;
-
- status_t initDecoder();
- status_t destroyDecoder();
- void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2GraphicBlock> &block);
- bool outputBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work);
- c2_status_t drainInternal(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool,
- const std::unique_ptr<C2Work> &work);
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftVpx);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_VPX_H_
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 9ac2791..b62b526 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -44,7 +44,7 @@
private:
enum {
- kNumBuffers = 16
+ kNumBuffers = 10
};
enum {
diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp
index 38d72e6..43318f2 100644
--- a/media/libstagefright/codecs/opus/dec/Android.bp
+++ b/media/libstagefright/codecs/opus/dec/Android.bp
@@ -1,40 +1,4 @@
cc_library_shared {
- name: "libstagefright_soft_c2opusdec",
-// vendor_available: true,
-// vndk: {
-// enabled: true,
-// },
-
- srcs: ["C2SoftOpus.cpp"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- diag: {
- cfi: true,
- },
- },
-
- shared_libs: [
- "liblog",
- "libutils",
- "libstagefright_codec2",
- "libstagefright_codec2_vndk",
- "libstagefright_foundation",
- "libstagefright_simple_c2component",
- "libopus",
- ],
-}
-
-cc_library_shared {
name: "libstagefright_soft_opusdec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/opus/dec/C2SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/C2SoftOpus.cpp
deleted file mode 100644
index 47fb6de..0000000
--- a/media/libstagefright/codecs/opus/dec/C2SoftOpus.cpp
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2018 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 "C2SoftOpus"
-#include <utils/Log.h>
-
-#include "C2SoftOpus.h"
-
-#include <C2PlatformSupport.h>
-#include <SimpleC2Interface.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/MediaDefs.h>
-
-extern "C" {
- #include <opus.h>
- #include <opus_multistream.h>
-}
-
-namespace android {
-
-constexpr char kComponentName[] = "c2.google.opus.decoder";
-
-static std::shared_ptr<C2ComponentInterface> BuildIntf(
- const char *name, c2_node_id_t id,
- std::function<void(C2ComponentInterface*)> deleter =
- std::default_delete<C2ComponentInterface>()) {
- return SimpleC2Interface::Builder(name, id, deleter)
- .inputFormat(C2FormatCompressed)
- .outputFormat(C2FormatAudio)
- .inputMediaType(MEDIA_MIMETYPE_AUDIO_OPUS)
- .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
- .build();
-}
-
-C2SoftOpus::C2SoftOpus(const char *name, c2_node_id_t id)
- : SimpleC2Component(BuildIntf(name, id)),
- mDecoder(nullptr) {
-}
-
-C2SoftOpus::~C2SoftOpus() {
- onRelease();
-}
-
-c2_status_t C2SoftOpus::onInit() {
- status_t err = initDecoder();
- return err == OK ? C2_OK : C2_NO_MEMORY;
-}
-
-c2_status_t C2SoftOpus::onStop() {
- if (mDecoder) {
- opus_multistream_decoder_destroy(mDecoder);
- mDecoder = nullptr;
- }
- memset(&mHeader, 0, sizeof(mHeader));
- mCodecDelay = 0;
- mSeekPreRoll = 0;
- mSamplesToDiscard = 0;
- mInputBufferCount = 0;
- mSignalledError = false;
- mSignalledOutputEos = false;
-
- return C2_OK;
-}
-
-void C2SoftOpus::onReset() {
- (void)onStop();
-}
-
-void C2SoftOpus::onRelease() {
- if (mDecoder) {
- opus_multistream_decoder_destroy(mDecoder);
- mDecoder = nullptr;
- }
-}
-
-status_t C2SoftOpus::initDecoder() {
- memset(&mHeader, 0, sizeof(mHeader));
- mCodecDelay = 0;
- mSeekPreRoll = 0;
- mSamplesToDiscard = 0;
- mInputBufferCount = 0;
- mSignalledError = false;
- mSignalledOutputEos = false;
-
- return OK;
-}
-
-c2_status_t C2SoftOpus::onFlush_sm() {
- if (mDecoder) {
- opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
- mSamplesToDiscard = mSeekPreRoll;
- mSignalledOutputEos = false;
- }
- return C2_OK;
-}
-
-c2_status_t C2SoftOpus::drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) {
- (void) pool;
- if (drainMode == NO_DRAIN) {
- ALOGW("drain with NO_DRAIN: no-op");
- return C2_OK;
- }
- if (drainMode == DRAIN_CHAIN) {
- ALOGW("DRAIN_CHAIN not supported");
- return C2_OMITTED;
- }
-
- return C2_OK;
-}
-
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
-}
-
-static uint16_t ReadLE16(const uint8_t *data, size_t data_size,
- uint32_t read_offset) {
- if (read_offset + 1 > data_size)
- return 0;
- uint16_t val;
- val = data[read_offset];
- val |= data[read_offset + 1] << 8;
- return val;
-}
-
-static const int kRate = 48000;
-
-// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
-// mappings for up to 8 channels. This information is part of the Vorbis I
-// Specification:
-// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
-static const int kMaxChannels = 8;
-
-// Maximum packet size used in Xiph's opusdec.
-static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
-
-// Default audio output channel layout. Used to initialize |stream_map| in
-// OpusHeader, and passed to opus_multistream_decoder_create() when the header
-// does not contain mapping information. The values are valid only for mono and
-// stereo output: Opus streams with more than 2 channels require a stream map.
-static const int kMaxChannelsWithDefaultLayout = 2;
-static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
-
-// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
-static bool ParseOpusHeader(const uint8_t *data, size_t data_size,
- OpusHeader* header) {
- // Size of the Opus header excluding optional mapping information.
- const size_t kOpusHeaderSize = 19;
-
- // Offset to the channel count byte in the Opus header.
- const size_t kOpusHeaderChannelsOffset = 9;
-
- // Offset to the pre-skip value in the Opus header.
- const size_t kOpusHeaderSkipSamplesOffset = 10;
-
- // Offset to the gain value in the Opus header.
- const size_t kOpusHeaderGainOffset = 16;
-
- // Offset to the channel mapping byte in the Opus header.
- const size_t kOpusHeaderChannelMappingOffset = 18;
-
- // Opus Header contains a stream map. The mapping values are in the header
- // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
- // data contains stream count, coupling information, and per channel mapping
- // values:
- // - Byte 0: Number of streams.
- // - Byte 1: Number coupled.
- // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
- // values.
- const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
- const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
- const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
-
- if (data_size < kOpusHeaderSize) {
- ALOGE("Header size is too small.");
- return false;
- }
- header->channels = *(data + kOpusHeaderChannelsOffset);
- if (header->channels <= 0 || header->channels > kMaxChannels) {
- ALOGE("Invalid Header, wrong channel count: %d", header->channels);
- return false;
- }
-
- header->skip_samples = ReadLE16(data,
- data_size,
- kOpusHeaderSkipSamplesOffset);
-
- header->gain_db = static_cast<int16_t>(ReadLE16(data,
- data_size,
- kOpusHeaderGainOffset));
-
- header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
- if (!header->channel_mapping) {
- if (header->channels > kMaxChannelsWithDefaultLayout) {
- ALOGE("Invalid Header, missing stream map.");
- return false;
- }
- header->num_streams = 1;
- header->num_coupled = header->channels > 1;
- header->stream_map[0] = 0;
- header->stream_map[1] = 1;
- return true;
- }
- if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
- ALOGE("Invalid stream map; insufficient data for current channel "
- "count: %d", header->channels);
- return false;
- }
- header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
- header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
- if (header->num_streams + header->num_coupled != header->channels) {
- ALOGE("Inconsistent channel mapping.");
- return false;
- }
- for (int i = 0; i < header->channels; ++i)
- header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
- return true;
-}
-
-// Convert nanoseconds to number of samples.
-static uint64_t ns_to_samples(uint64_t ns, int rate) {
- return static_cast<double>(ns) * rate / 1000000000;
-}
-
-void C2SoftOpus::process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) {
- work->result = C2_OK;
- work->workletsProcessed = 0u;
- if (mSignalledError || mSignalledOutputEos) {
- work->result = C2_BAD_VALUE;
- return;
- }
-
- const C2ConstLinearBlock inBuffer = work->input.buffers[0]->data().linearBlocks().front();
- bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
- size_t inOffset = inBuffer.offset();
- size_t inSize = inBuffer.size();
- C2ReadView rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
- if (inSize && rView.error()) {
- ALOGE("read view map failed %d", rView.error());
- work->result = C2_CORRUPTED;
- return;
- }
- if (inSize == 0) {
- fillEmptyWork(work);
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- return;
- }
-
- ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
- (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
- const uint8_t *data = rView.data() + inOffset;
- if (mInputBufferCount < 3) {
- if (mInputBufferCount == 0) {
- if (!ParseOpusHeader(data, inSize, &mHeader)) {
- ALOGE("Encountered error while Parsing Opus Header.");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- uint8_t channel_mapping[kMaxChannels] = {0};
- if (mHeader.channels <= kMaxChannelsWithDefaultLayout) {
- memcpy(&channel_mapping,
- kDefaultOpusChannelLayout,
- kMaxChannelsWithDefaultLayout);
- } else {
- memcpy(&channel_mapping,
- mHeader.stream_map,
- mHeader.channels);
- }
- int status = OPUS_INVALID_STATE;
- mDecoder = opus_multistream_decoder_create(kRate,
- mHeader.channels,
- mHeader.num_streams,
- mHeader.num_coupled,
- channel_mapping,
- &status);
- if (!mDecoder || status != OPUS_OK) {
- ALOGE("opus_multistream_decoder_create failed status = %s",
- opus_strerror(status));
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- status = opus_multistream_decoder_ctl(mDecoder,
- OPUS_SET_GAIN(mHeader.gain_db));
- if (status != OPUS_OK) {
- ALOGE("Failed to set OPUS header gain; status = %s",
- opus_strerror(status));
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- } else {
- if (inSize < 8) {
- ALOGE("Input sample size is too small.");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
- int64_t samples = ns_to_samples( *(reinterpret_cast<int64_t*>
- (const_cast<uint8_t *> (data))), kRate);
- if (mInputBufferCount == 1) {
- mCodecDelay = samples;
- mSamplesToDiscard = mCodecDelay;
- }
- else {
- mSeekPreRoll = samples;
- }
- }
-
- ++mInputBufferCount;
- fillEmptyWork(work);
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
- return;
- }
-
- // Ignore CSD re-submissions.
- if ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
- fillEmptyWork(work);
- return;
- }
-
- // When seeking to zero, |mCodecDelay| samples has to be discarded
- // instead of |mSeekPreRoll| samples (as we would when seeking to any
- // other timestamp).
- if (work->input.ordinal.timestamp.peeku() == 0) mSamplesToDiscard = mCodecDelay;
-
- std::shared_ptr<C2LinearBlock> block;
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- c2_status_t err = pool->fetchLinearBlock(
- kMaxNumSamplesPerBuffer * kMaxChannels * sizeof(int16_t),
- usage, &block);
- if (err != C2_OK) {
- ALOGE("fetchLinearBlock for Output failed with status %d", err);
- work->result = C2_NO_MEMORY;
- return;
- }
- C2WriteView wView = block->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
- work->result = C2_CORRUPTED;
- return;
- }
-
- int numSamples = opus_multistream_decode(mDecoder,
- data,
- inSize,
- reinterpret_cast<int16_t *> (wView.data()),
- kMaxOpusOutputPacketSizeSamples,
- 0);
- if (numSamples < 0) {
- ALOGE("opus_multistream_decode returned numSamples %d", numSamples);
- numSamples = 0;
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- return;
- }
-
- int outOffset = 0;
- if (mSamplesToDiscard > 0) {
- if (mSamplesToDiscard > numSamples) {
- mSamplesToDiscard -= numSamples;
- numSamples = 0;
- } else {
- numSamples -= mSamplesToDiscard;
- outOffset = mSamplesToDiscard * sizeof(int16_t) * mHeader.channels;
- mSamplesToDiscard = 0;
- }
- }
-
- if (numSamples) {
- int outSize = numSamples * sizeof(int16_t) * mHeader.channels;
- ALOGV("out buffer attr. offset %d size %d ", outOffset, outSize);
-
- work->worklets.front()->output.flags = work->input.flags;
- work->worklets.front()->output.buffers.clear();
- work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, outOffset, outSize));
- work->worklets.front()->output.ordinal = work->input.ordinal;
- work->workletsProcessed = 1u;
- } else {
- fillEmptyWork(work);
- block.reset();
- }
- if (eos) {
- mSignalledOutputEos = true;
- ALOGV("signalled EOS");
- }
-}
-
-class C2SoftOpusDecFactory : public C2ComponentFactory {
-public:
- virtual c2_status_t createComponent(
- c2_node_id_t id,
- std::shared_ptr<C2Component>* const component,
- std::function<void(C2Component*)> deleter) override {
- *component = std::shared_ptr<C2Component>(new C2SoftOpus(kComponentName, id), deleter);
- return C2_OK;
- }
-
- virtual c2_status_t createInterface(
- c2_node_id_t id,
- std::shared_ptr<C2ComponentInterface>* const interface,
- std::function<void(C2ComponentInterface*)> deleter) override {
- *interface = BuildIntf(kComponentName, id, deleter);
- return C2_OK;
- }
-
- virtual ~C2SoftOpusDecFactory() override = default;
-};
-
-} // namespace android
-
-extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
- ALOGV("in %s", __func__);
- return new ::android::C2SoftOpusDecFactory();
-}
-
-extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
- ALOGV("in %s", __func__);
- delete factory;
-}
diff --git a/media/libstagefright/codecs/opus/dec/C2SoftOpus.h b/media/libstagefright/codecs/opus/dec/C2SoftOpus.h
deleted file mode 100644
index 70ad2de..0000000
--- a/media/libstagefright/codecs/opus/dec/C2SoftOpus.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#ifndef C2_SOFT_OPUS_H_
-#define C2_SOFT_OPUS_H_
-
-#include <SimpleC2Component.h>
-
-#include <media/stagefright/foundation/ABase.h>
-
-struct OpusMSDecoder;
-
-namespace android {
-
-struct OpusHeader {
- int channels;
- int skip_samples;
- int channel_mapping;
- int num_streams;
- int num_coupled;
- int16_t gain_db;
- uint8_t stream_map[8];
-};
-
-struct C2SoftOpus : public SimpleC2Component {
- C2SoftOpus(const char *name, c2_node_id_t id);
- virtual ~C2SoftOpus();
-
- // From SimpleC2Component
- c2_status_t onInit() override;
- c2_status_t onStop() override;
- void onReset() override;
- void onRelease() override;
- c2_status_t onFlush_sm() override;
- void process(
- const std::unique_ptr<C2Work> &work,
- const std::shared_ptr<C2BlockPool> &pool) override;
- c2_status_t drain(
- uint32_t drainMode,
- const std::shared_ptr<C2BlockPool> &pool) override;
-private:
- enum {
- kMaxNumSamplesPerBuffer = 960 * 6
- };
-
- OpusMSDecoder *mDecoder;
- OpusHeader mHeader;
-
- int64_t mCodecDelay;
- int64_t mSeekPreRoll;
- int64_t mSamplesToDiscard;
- size_t mInputBufferCount;
- bool mSignalledError;
- bool mSignalledOutputEos;
-
- status_t initDecoder();
-
- DISALLOW_EVIL_CONSTRUCTORS(C2SoftOpus);
-};
-
-} // namespace android
-
-#endif // C2_SOFT_OPUS_H_
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 581e51b..8d486cf 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -9,6 +9,8 @@
"FLACDecoder.cpp",
],
+ export_include_dirs: [ "." ],
+
include_dirs: [
"external/flac/include",
"frameworks/av/media/libstagefright/include",
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
index 8c7137c..e0e9211 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.cpp
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -220,9 +220,10 @@
}
// static
-sp<FLACDecoder> FLACDecoder::Create() {
- sp<FLACDecoder> decoder = new FLACDecoder();
- if (decoder->init() != OK) {
+FLACDecoder *FLACDecoder::Create() {
+ FLACDecoder *decoder = new (std::nothrow) FLACDecoder();
+ if (decoder == NULL || decoder->init() != OK) {
+ delete decoder;
return NULL;
}
return decoder;
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
index 36282a8..1a33cae 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.h
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -26,14 +26,14 @@
namespace android {
// packet based FLAC decoder, wrapps libFLAC stream decoder.
-class FLACDecoder : public RefBase {
+class FLACDecoder {
public:
enum {
kMaxChannels = 8,
};
- static sp<FLACDecoder> Create();
+ static FLACDecoder *Create();
FLAC__StreamMetadata_StreamInfo getStreamInfo() const {
return mStreamInfo;
@@ -43,10 +43,10 @@
status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
short *outBuffer, size_t *outBufferLen);
void flush();
+ virtual ~FLACDecoder();
protected:
FLACDecoder();
- virtual ~FLACDecoder() override;
private:
// stream properties
diff --git a/media/libstagefright/include/C2OMXNode.h b/media/libstagefright/include/C2OMXNode.h
deleted file mode 100644
index 3c007c4..0000000
--- a/media/libstagefright/include/C2OMXNode.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#ifndef C2_OMX_NODE_H_
-#define C2_OMX_NODE_H_
-
-#include <atomic>
-
-#include <android/IOMXBufferSource.h>
-#include <media/IOMX.h>
-#include <media/OMXBuffer.h>
-
-namespace android {
-
-/**
- * IOmxNode implementation around codec 2.0 component, only to be used in
- * IGraphicBufferSource::configure. Only subset of IOmxNode API is implemented
- * and others are left as stub. As a result, one cannot expect this IOmxNode
- * to work in any other usage than IGraphicBufferSource.
- */
-struct C2OMXNode : public BnOMXNode {
- // TODO: this should take android::hardware::media::c2::V1_0::IComponent
- explicit C2OMXNode(const std::shared_ptr<C2Component> &comp);
- ~C2OMXNode() override = default;
-
- // IOMXNode
- status_t freeNode() override;
- status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) override;
- status_t getParameter(
- OMX_INDEXTYPE index, void *params, size_t size) override;
- status_t setParameter(
- OMX_INDEXTYPE index, const void *params, size_t size) override;
- status_t getConfig(
- OMX_INDEXTYPE index, void *params, size_t size) override;
- status_t setConfig(
- OMX_INDEXTYPE index, const void *params, size_t size) override;
- status_t setPortMode(OMX_U32 port_index, IOMX::PortMode mode) override;
- status_t prepareForAdaptivePlayback(
- OMX_U32 portIndex, OMX_BOOL enable,
- OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) override;
- status_t configureVideoTunnelMode(
- OMX_U32 portIndex, OMX_BOOL tunneled,
- OMX_U32 audioHwSync, native_handle_t **sidebandHandle) override;
- status_t getGraphicBufferUsage(
- OMX_U32 port_index, OMX_U32* usage) override;
- status_t setInputSurface(
- const sp<IOMXBufferSource> &bufferSource) override;
- status_t allocateSecureBuffer(
- OMX_U32 port_index, size_t size, buffer_id *buffer,
- void **buffer_data, sp<NativeHandle> *native_handle) override;
- status_t useBuffer(
- OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) override;
- status_t freeBuffer(
- OMX_U32 port_index, buffer_id buffer) override;
- status_t fillBuffer(
- buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) override;
- status_t emptyBuffer(
- buffer_id buffer, const OMXBuffer &omxBuf,
- OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) override;
- status_t getExtensionIndex(
- const char *parameter_name,
- OMX_INDEXTYPE *index) override;
- status_t dispatchMessage(const omx_message &msg) override;
-
- sp<IOMXBufferSource> getSource();
-
-private:
- std::weak_ptr<C2Component> mComp;
- sp<IOMXBufferSource> mBufferSource;
- std::shared_ptr<C2Allocator> mAllocator;
- std::atomic_uint64_t mFrameIndex;
-};
-
-} // namespace android
-
-#endif // C2_OMX_NODE_H_
diff --git a/media/libstagefright/include/CCodecBufferChannel.h b/media/libstagefright/include/CCodecBufferChannel.h
deleted file mode 100644
index 51eee10..0000000
--- a/media/libstagefright/include/CCodecBufferChannel.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2017, 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.
- */
-
-#ifndef CCODEC_BUFFER_CHANNEL_H_
-
-#define CCODEC_BUFFER_CHANNEL_H_
-
-#include <map>
-#include <memory>
-#include <mutex>
-#include <vector>
-
-#include <C2Buffer.h>
-#include <C2Component.h>
-
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
-#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/CodecBase.h>
-#include <media/ICrypto.h>
-
-#include "InputSurfaceWrapper.h"
-
-namespace android {
-
-using ::android::hardware::media::c2::V1_0::implementation::InputSurface;
-using ::android::hardware::media::c2::V1_0::implementation::InputSurfaceConnection;
-
-/**
- * BufferChannelBase implementation for CCodec.
- */
-class CCodecBufferChannel
- : public BufferChannelBase, public std::enable_shared_from_this<CCodecBufferChannel> {
-public:
- CCodecBufferChannel(const std::function<void(status_t, enum ActionCode)> &onError);
- virtual ~CCodecBufferChannel();
-
- // BufferChannelBase interface
- virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
- virtual status_t queueSecureInputBuffer(
- const sp<MediaCodecBuffer> &buffer,
- bool secure,
- const uint8_t *key,
- const uint8_t *iv,
- CryptoPlugin::Mode mode,
- CryptoPlugin::Pattern pattern,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- AString *errorDetailMsg) override;
- virtual status_t renderOutputBuffer(
- const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
- virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
- virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
- virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
-
- // Methods below are interface for CCodec to use.
-
- /**
- * Set the component object for buffer processing.
- */
- void setComponent(const std::shared_ptr<C2Component> &component);
-
- /**
- * Set output graphic surface for rendering.
- */
- status_t setSurface(const sp<Surface> &surface);
-
- /**
- * Set GraphicBufferSource object from which the component extracts input
- * buffers.
- */
- status_t setInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
-
- /**
- * Start queueing buffers to the component. This object should never queue
- * buffers before this call.
- */
- status_t start(const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat);
-
- /**
- * Stop queueing buffers to the component. This object should never queue
- * buffers after this call, until start() is called.
- */
- void stop();
-
- void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork);
-
- /**
- * Notify input client about work done.
- *
- * @param workItems finished work item.
- */
- void onWorkDone(const std::unique_ptr<C2Work> &work);
-
- // Internal classes
- class Buffers;
- class InputBuffers;
- class OutputBuffers;
-
-private:
- class QueueGuard;
-
- /**
- * Special mutex-like object with the following properties:
- *
- * - At STOPPED state (initial, or after stop())
- * - QueueGuard object gets created at STOPPED state, and the client is
- * supposed to return immediately.
- * - At RUNNING state (after start())
- * - Each QueueGuard object
- */
- class QueueSync {
- public:
- /**
- * At construction the sync object is in STOPPED state.
- */
- inline QueueSync() : mCount(-1) {}
- ~QueueSync() = default;
-
- /**
- * Transition to RUNNING state when stopped. No-op if already in RUNNING
- * state.
- */
- void start();
-
- /**
- * At RUNNING state, wait until all QueueGuard object created during
- * RUNNING state are destroyed, and then transition to STOPPED state.
- * No-op if already in STOPPED state.
- */
- void stop();
-
- private:
- std::mutex mMutex;
- std::atomic_int32_t mCount;
-
- friend class CCodecBufferChannel::QueueGuard;
- };
-
- class QueueGuard {
- public:
- QueueGuard(QueueSync &sync);
- ~QueueGuard();
- inline bool isRunning() { return mRunning; }
-
- private:
- QueueSync &mSync;
- bool mRunning;
- };
-
- void feedInputBufferIfAvailable();
-
- QueueSync mSync;
- sp<MemoryDealer> mDealer;
- sp<IMemory> mDecryptDestination;
- int32_t mHeapSeqNum;
-
- std::shared_ptr<C2Component> mComponent;
- std::function<void(status_t, enum ActionCode)> mOnError;
- std::shared_ptr<C2BlockPool> mInputAllocator;
- QueueSync mQueueSync;
-
- Mutexed<std::unique_ptr<InputBuffers>> mInputBuffers;
- Mutexed<std::unique_ptr<OutputBuffers>> mOutputBuffers;
-
- std::atomic_uint64_t mFrameIndex;
- std::atomic_uint64_t mFirstValidFrameIndex;
-
- sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
- Mutexed<sp<Surface>> mSurface;
-
- std::shared_ptr<InputSurfaceWrapper> mInputSurface;
-
- inline bool hasCryptoOrDescrambler() {
- return mCrypto != NULL || mDescrambler != NULL;
- }
-};
-
-} // namespace android
-
-#endif // CCODEC_BUFFER_CHANNEL_H_
diff --git a/media/libstagefright/include/Codec2Buffer.h b/media/libstagefright/include/Codec2Buffer.h
deleted file mode 100644
index eeb889d..0000000
--- a/media/libstagefright/include/Codec2Buffer.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2017, 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.
- */
-
-#ifndef CODEC2_BUFFER_H_
-
-#define CODEC2_BUFFER_H_
-
-#include <C2Buffer.h>
-
-#include <media/hardware/VideoAPI.h>
-#include <media/MediaCodecBuffer.h>
-
-namespace android {
-
-class Codec2Buffer : public MediaCodecBuffer {
-public:
- using MediaCodecBuffer::MediaCodecBuffer;
- ~Codec2Buffer() override = default;
-
- /**
- * \return C2Buffer object represents this buffer.
- */
- virtual std::shared_ptr<C2Buffer> asC2Buffer() = 0;
-
- /**
- * Test if we can copy the content of |buffer| into this object.
- *
- * \param buffer C2Buffer object to copy.
- * \return true if the content of buffer can be copied over to this buffer
- * false otherwise.
- */
- virtual bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
- (void)buffer;
- return false;
- }
-
- /**
- * Copy the content of |buffer| into this object. This method assumes that
- * canCopy() check already passed.
- *
- * \param buffer C2Buffer object to copy.
- * \return true if successful
- * false otherwise.
- */
- virtual bool copy(const std::shared_ptr<C2Buffer> &buffer) {
- (void)buffer;
- return false;
- }
-
-protected:
- /**
- * canCopy() implementation for linear buffers.
- */
- bool canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const;
-
- /**
- * copy() implementation for linear buffers.
- */
- bool copyLinear(const std::shared_ptr<C2Buffer> &buffer);
-};
-
-/**
- * MediaCodecBuffer implementation on top of local linear buffer. This cannot
- * cross process boundary so asC2Buffer() returns only nullptr.
- */
-class LocalLinearBuffer : public Codec2Buffer {
-public:
- using Codec2Buffer::Codec2Buffer;
-
- std::shared_ptr<C2Buffer> asC2Buffer() override { return nullptr; }
- bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
- bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
-};
-
-/**
- * MediaCodecBuffer implementation to be used only as a dummy wrapper around a
- * C2Buffer object.
- */
-class DummyContainerBuffer : public Codec2Buffer {
-public:
- DummyContainerBuffer(
- const sp<AMessage> &format,
- const std::shared_ptr<C2Buffer> &buffer = nullptr);
-
- std::shared_ptr<C2Buffer> asC2Buffer() override;
- bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
- bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
-
-private:
- std::shared_ptr<C2Buffer> mBufferRef;
-};
-
-/**
- * MediaCodecBuffer implementation wraps around C2LinearBlock.
- */
-class LinearBlockBuffer : public Codec2Buffer {
-public:
- /**
- * Allocate a new LinearBufferBlock wrapping around C2LinearBlock object.
- *
- * \param format mandatory buffer format for MediaCodecBuffer
- * \param block C2LinearBlock object to wrap around.
- * \return LinearBlockBuffer object with writable mapping.
- * nullptr if unsuccessful.
- */
- static sp<LinearBlockBuffer> Allocate(
- const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block);
-
- virtual ~LinearBlockBuffer() = default;
-
- std::shared_ptr<C2Buffer> asC2Buffer() override;
- bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
- bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
-
-private:
- LinearBlockBuffer(
- const sp<AMessage> &format,
- C2WriteView &&writeView,
- const std::shared_ptr<C2LinearBlock> &block);
- LinearBlockBuffer() = delete;
-
- C2WriteView mWriteView;
- std::shared_ptr<C2LinearBlock> mBlock;
-};
-
-/**
- * MediaCodecBuffer implementation wraps around C2ConstLinearBlock.
- */
-class ConstLinearBlockBuffer : public Codec2Buffer {
-public:
- /**
- * Allocate a new ConstLinearBlockBuffer wrapping around C2Buffer object.
- *
- * \param format mandatory buffer format for MediaCodecBuffer
- * \param buffer linear C2Buffer object to wrap around.
- * \return ConstLinearBlockBuffer object with readable mapping.
- * nullptr if unsuccessful.
- */
- static sp<ConstLinearBlockBuffer> Allocate(
- const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer);
-
- virtual ~ConstLinearBlockBuffer() = default;
-
- std::shared_ptr<C2Buffer> asC2Buffer() override;
-
-private:
- ConstLinearBlockBuffer(
- const sp<AMessage> &format,
- C2ReadView &&readView,
- const std::shared_ptr<C2Buffer> &buffer);
- ConstLinearBlockBuffer() = delete;
-
- C2ReadView mReadView;
- std::shared_ptr<C2Buffer> mBufferRef;
-};
-
-/**
- * MediaCodecBuffer implementation wraps around C2GraphicBlock.
- *
- * This object exposes the underlying bits via accessor APIs and "image-data"
- * metadata, created automatically at allocation time.
- */
-class GraphicBlockBuffer : public Codec2Buffer {
-public:
- /**
- * Allocate a new GraphicBlockBuffer wrapping around C2GraphicBlock object.
- * If |block| is not in good color formats, it allocates YV12 local buffer
- * and copies the content over at asC2Buffer().
- *
- * \param format mandatory buffer format for MediaCodecBuffer
- * \param block C2GraphicBlock object to wrap around.
- * \param alloc a function to allocate backing ABuffer if needed.
- * \return GraphicBlockBuffer object with writable mapping.
- * nullptr if unsuccessful.
- */
- static sp<GraphicBlockBuffer> Allocate(
- const sp<AMessage> &format,
- const std::shared_ptr<C2GraphicBlock> &block,
- std::function<sp<ABuffer>(size_t)> alloc);
-
- std::shared_ptr<C2Buffer> asC2Buffer() override;
-
- virtual ~GraphicBlockBuffer() = default;
-
-private:
- GraphicBlockBuffer(
- const sp<AMessage> &format,
- const sp<ABuffer> &buffer,
- C2GraphicView &&view,
- const std::shared_ptr<C2GraphicBlock> &block,
- const sp<ABuffer> &imageData,
- bool wrapped);
- GraphicBlockBuffer() = delete;
-
- inline MediaImage2 *imageData() { return (MediaImage2 *)mImageData->data(); }
-
- C2GraphicView mView;
- std::shared_ptr<C2GraphicBlock> mBlock;
- sp<ABuffer> mImageData;
- const bool mWrapped;
-};
-
-/**
- * MediaCodecBuffer implementation wraps around graphic C2Buffer object.
- *
- * This object exposes the underlying bits via accessor APIs and "image-data"
- * metadata, created automatically at allocation time.
- */
-class ConstGraphicBlockBuffer : public Codec2Buffer {
-public:
- /**
- * Allocate a new ConstGraphicBlockBuffer wrapping around C2Buffer object.
- * If |buffer| is not in good color formats, it allocates YV12 local buffer
- * and copies the content of |buffer| over to expose.
- *
- * \param format mandatory buffer format for MediaCodecBuffer
- * \param buffer graphic C2Buffer object to wrap around.
- * \param alloc a function to allocate backing ABuffer if needed.
- * \return ConstGraphicBlockBuffer object with readable mapping.
- * nullptr if unsuccessful.
- */
- static sp<ConstGraphicBlockBuffer> Allocate(
- const sp<AMessage> &format,
- const std::shared_ptr<C2Buffer> &buffer,
- std::function<sp<ABuffer>(size_t)> alloc);
-
- /**
- * Allocate a new ConstGraphicBlockBuffer which allocates YV12 local buffer
- * and copies the content of |buffer| over to expose.
- *
- * \param format mandatory buffer format for MediaCodecBuffer
- * \param alloc a function to allocate backing ABuffer if needed.
- * \return ConstGraphicBlockBuffer object with no wrapping buffer.
- */
- static sp<ConstGraphicBlockBuffer> AllocateEmpty(
- const sp<AMessage> &format,
- std::function<sp<ABuffer>(size_t)> alloc);
-
- std::shared_ptr<C2Buffer> asC2Buffer() override;
- bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
- bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
-
- virtual ~ConstGraphicBlockBuffer() = default;
-
-private:
- ConstGraphicBlockBuffer(
- const sp<AMessage> &format,
- const sp<ABuffer> &aBuffer,
- std::unique_ptr<const C2GraphicView> &&view,
- const std::shared_ptr<C2Buffer> &buffer,
- const sp<ABuffer> &imageData,
- bool wrapped);
- ConstGraphicBlockBuffer() = delete;
-
- sp<ABuffer> mImageData;
- std::unique_ptr<const C2GraphicView> mView;
- std::shared_ptr<C2Buffer> mBufferRef;
- const bool mWrapped;
-};
-
-} // namespace android
-
-#endif // CODEC2_BUFFER_H_
diff --git a/media/libstagefright/include/InputSurfaceWrapper.h b/media/libstagefright/include/InputSurfaceWrapper.h
deleted file mode 100644
index a4d8f29..0000000
--- a/media/libstagefright/include/InputSurfaceWrapper.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#ifndef INPUT_SURFACE_WRAPPER_H_
-
-#define INPUT_SURFACE_WRAPPER_H_
-
-namespace android {
-
-/**
- * Wrapper interface around InputSurface.
- */
-class InputSurfaceWrapper {
-public:
- virtual ~InputSurfaceWrapper() = default;
-
- /**
- * Connect the surface with |comp| and start pushing buffers. A surface can
- * connect to at most one component at a time.
- *
- * \return OK successfully connected to |comp|
- * \return ALREADY_EXISTS already connected to another component.
- */
- virtual status_t connect(const std::shared_ptr<C2Component> &comp) = 0;
-
- /**
- * Disconnect the surface from the component if any.
- */
- virtual void disconnect() = 0;
-
- // TODO: intf()
-};
-
-} // namespace android
-
-#endif // INPUT_SURFACE_WRAPPER_H_
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index fa22003..1a5304b 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -253,6 +253,7 @@
sp<AMessage> mLastOutputFormat;
bool mIsVideo;
+ bool mIsImage;
bool mIsEncoder;
bool mFatalError;
bool mShutdownInProgress;
@@ -489,11 +490,12 @@
status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg);
status_t setupH263EncoderParameters(const sp<AMessage> &msg);
status_t setupAVCEncoderParameters(const sp<AMessage> &msg);
- status_t setupHEVCEncoderParameters(const sp<AMessage> &msg);
+ status_t setupHEVCEncoderParameters(const sp<AMessage> &msg, sp<AMessage> &outputFormat);
status_t setupVPXEncoderParameters(const sp<AMessage> &msg, sp<AMessage> &outputFormat);
status_t verifySupportForProfileAndLevel(int32_t profile, int32_t level);
+ status_t configureImageGrid(const sp<AMessage> &msg, sp<AMessage> &outputFormat);
status_t configureBitrate(
OMX_VIDEO_CONTROLRATETYPE bitrateMode, int32_t bitrate, int32_t quality = 0);
void configureEncoderLatency(const sp<AMessage> &msg);
diff --git a/media/libstagefright/include/media/stagefright/CCodec.h b/media/libstagefright/include/media/stagefright/CCodec.h
deleted file mode 100644
index 078b03e..0000000
--- a/media/libstagefright/include/media/stagefright/CCodec.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef C_CODEC_H_
-#define C_CODEC_H_
-
-#include <chrono>
-
-#include <C2Component.h>
-
-#include <android/native_window.h>
-#include <media/hardware/MetadataBufferType.h>
-#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/CodecBase.h>
-#include <media/stagefright/FrameRenderTracker.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/SkipCutBuffer.h>
-#include <utils/NativeHandle.h>
-#include <hardware/gralloc.h>
-#include <nativebase/nativebase.h>
-
-namespace android {
-
-class CCodecBufferChannel;
-class InputSurfaceWrapper;
-
-class CCodec : public CodecBase {
-public:
- CCodec();
-
- virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
- virtual void initiateAllocateComponent(const sp<AMessage> &msg) override;
- virtual void initiateConfigureComponent(const sp<AMessage> &msg) override;
- virtual void initiateCreateInputSurface() override;
- virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface) override;
- virtual void initiateStart() override;
- virtual void initiateShutdown(bool keepComponentAllocated = false) override;
-
- virtual status_t setSurface(const sp<Surface> &surface) override;
-
- virtual void signalFlush() override;
- virtual void signalResume() override;
-
- virtual void signalSetParameters(const sp<AMessage> &msg) override;
- virtual void signalEndOfInputStream() override;
- virtual void signalRequestIDRFrame() override;
-
- void initiateReleaseIfStuck();
- void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
-
-protected:
- virtual ~CCodec();
-
- virtual void onMessageReceived(const sp<AMessage> &msg) override;
-
-private:
- typedef std::chrono::time_point<std::chrono::steady_clock> TimePoint;
-
- status_t tryAndReportOnError(std::function<status_t()> job);
-
- void initiateStop();
- void initiateRelease(bool sendCallback = true);
-
- void allocate(const AString &componentName);
- void configure(const sp<AMessage> &msg);
- void start();
- void stop();
- void flush();
- void release(bool sendCallback);
-
- void createInputSurface();
- void setInputSurface(const sp<PersistentSurface> &surface);
- status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
-
- void setDeadline(const TimePoint &deadline, const char *name);
-
- enum {
- kWhatAllocate,
- kWhatConfigure,
- kWhatStart,
- kWhatFlush,
- kWhatStop,
- kWhatRelease,
- kWhatCreateInputSurface,
- kWhatSetInputSurface,
- kWhatWorkDone,
- };
-
- enum {
- RELEASED,
- ALLOCATED,
- FLUSHED,
- RUNNING,
-
- ALLOCATING, // RELEASED -> ALLOCATED
- STARTING, // ALLOCATED -> RUNNING
- STOPPING, // RUNNING -> ALLOCATED
- FLUSHING, // RUNNING -> FLUSHED
- RESUMING, // FLUSHED -> RUNNING
- RELEASING, // {ANY EXCEPT RELEASED} -> RELEASED
- };
-
- struct State {
- inline State() : mState(RELEASED) {}
- inline int get() const { return mState; }
- inline void set(int newState) { mState = newState; }
-
- std::shared_ptr<C2Component> comp;
- private:
- int mState;
- };
-
- struct Formats {
- sp<AMessage> inputFormat;
- sp<AMessage> outputFormat;
- };
-
- struct NamedTimePoint {
- inline void set(
- const TimePoint &timePoint,
- const char *name) {
- mTimePoint = timePoint;
- mName = name;
- }
-
- inline TimePoint get() const { return mTimePoint; }
- inline const char *getName() const { return mName; }
- private:
- TimePoint mTimePoint;
- const char *mName;
- };
-
- Mutexed<State> mState;
- std::shared_ptr<CCodecBufferChannel> mChannel;
- std::shared_ptr<C2Component::Listener> mListener;
- Mutexed<NamedTimePoint> mDeadline;
- Mutexed<Formats> mFormats;
- Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
-
- DISALLOW_EVIL_CONSTRUCTORS(CCodec);
-};
-
-} // namespace android
-
-#endif // C_CODEC_H_
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 268662f..1cbf865 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -222,9 +222,7 @@
virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
virtual void signalEndOfInputStream() = 0;
- /*
- * Codec-related defines
- */
+ typedef CodecBase *(*CreateCodecFunc)(void);
protected:
CodecBase() = default;
@@ -324,4 +322,3 @@
} // namespace android
#endif // CODEC_BASE_H_
-
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 2a062cc..7b41362 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -195,6 +195,7 @@
uint32_t type;
int32_t width;
int32_t height;
+ int32_t rotation;
sp<ABuffer> hvcc;
} ItemProperty;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index e7faea5..ef8de1f 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -184,6 +184,8 @@
status_t getName(AString *componentName) const;
+ status_t getCodecInfo(sp<MediaCodecInfo> *codecInfo) const;
+
status_t getMetrics(MediaAnalyticsItem * &reply);
status_t setParameters(const sp<AMessage> ¶ms);
@@ -248,6 +250,7 @@
kWhatRequestIDRFrame = 'ridr',
kWhatRequestActivityNotification = 'racN',
kWhatGetName = 'getN',
+ kWhatGetCodecInfo = 'gCoI',
kWhatSetParameters = 'setP',
kWhatSetCallback = 'setC',
kWhatSetNotification = 'setN',
@@ -308,6 +311,7 @@
sp<ALooper> mCodecLooper;
sp<CodecBase> mCodec;
AString mComponentName;
+ sp<MediaCodecInfo> mCodecInfo;
sp<AReplyToken> mReplyID;
uint32_t mFlags;
status_t mStickyError;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
index d46fe85..e44b0a4 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecList.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h
@@ -18,10 +18,11 @@
#define MEDIA_CODEC_LIST_H_
-#include <initializer_list>
+#include <vector>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecListWriter.h>
#include <media/IMediaCodecList.h>
#include <media/MediaCodecInfo.h>
@@ -37,8 +38,6 @@
struct AMessage;
-struct MediaCodecListBuilderBase;
-
struct MediaCodecList : public BnMediaCodecList {
static sp<IMediaCodecList> getInstance();
@@ -74,8 +73,7 @@
const char *mime,
bool createEncoder,
uint32_t flags,
- Vector<AString> *matchingCodecs,
- Vector<AString> *owners = nullptr);
+ Vector<AString> *matchingCodecs);
static bool isSoftwareCodec(const AString &componentName);
@@ -98,7 +96,7 @@
* This constructor will call `buildMediaCodecList()` from the given
* `MediaCodecListBuilderBase` objects.
*/
- MediaCodecList(std::initializer_list<MediaCodecListBuilderBase*> builders);
+ MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders);
~MediaCodecList();
@@ -106,66 +104,6 @@
MediaCodecList(const MediaCodecList&) = delete;
MediaCodecList& operator=(const MediaCodecList&) = delete;
-
- friend MediaCodecListWriter;
-};
-
-/**
- * This class is to be used by a `MediaCodecListBuilderBase` instance to add
- * information to the associated `MediaCodecList` object.
- */
-struct MediaCodecListWriter {
- /**
- * Add a key-value pair to a `MediaCodecList`'s global settings.
- *
- * @param key Key.
- * @param value Value.
- */
- void addGlobalSetting(const char* key, const char* value);
- /**
- * Create an add a new `MediaCodecInfo` object to a `MediaCodecList`, and
- * return a `MediaCodecInfoWriter` object associated with the newly added
- * `MediaCodecInfo`.
- *
- * @return The `MediaCodecInfoWriter` object associated with the newly
- * added `MediaCodecInfo` object.
- */
- std::unique_ptr<MediaCodecInfoWriter> addMediaCodecInfo();
-private:
- /**
- * The associated `MediaCodecList` object.
- */
- MediaCodecList* mList;
-
- /**
- * Construct this writer object associated with the given `MediaCodecList`
- * object.
- *
- * @param list The "base" `MediaCodecList` object.
- */
- MediaCodecListWriter(MediaCodecList* list);
-
- friend MediaCodecList;
-};
-
-/**
- * This interface is to be used by `MediaCodecList` to fill its members with
- * appropriate information. `buildMediaCodecList()` will be called from a
- * `MediaCodecList` object during its construction.
- */
-struct MediaCodecListBuilderBase {
- /**
- * Build the `MediaCodecList` via the given `MediaCodecListWriter` interface.
- *
- * @param writer The writer interface.
- * @return The status of the construction. `NO_ERROR` means success.
- */
- virtual status_t buildMediaCodecList(MediaCodecListWriter* writer) = 0;
-
- /**
- * The default destructor does nothing.
- */
- virtual ~MediaCodecListBuilderBase();
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
new file mode 100644
index 0000000..59f57c7
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+#ifndef MEDIA_CODEC_LIST_WRITER_H_
+
+#define MEDIA_CODEC_LIST_WRITER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaCodecListWriter.h>
+#include <media/MediaCodecInfo.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to add
+ * information to the destination `MediaCodecList` object.
+ */
+struct MediaCodecListWriter {
+ /**
+ * Add a key-value pair to a `MediaCodecList`'s global settings.
+ *
+ * @param key Key.
+ * @param value Value.
+ */
+ void addGlobalSetting(const char* key, const char* value);
+ /**
+ * Create an add a new `MediaCodecInfo` object for a `MediaCodecList`, and
+ * return a `MediaCodecInfoWriter` object associated with the newly added
+ * `MediaCodecInfo`.
+ *
+ * @return The `MediaCodecInfoWriter` object associated with the newly
+ * added `MediaCodecInfo` object.
+ */
+ std::unique_ptr<MediaCodecInfoWriter> addMediaCodecInfo();
+private:
+ MediaCodecListWriter() = default;
+
+ void writeGlobalSettings(const sp<AMessage> &globalSettings) const;
+ void writeCodecInfos(std::vector<sp<MediaCodecInfo>> *codecInfos) const;
+
+ std::vector<std::pair<std::string, std::string>> mGlobalSettings;
+ std::vector<sp<MediaCodecInfo>> mCodecInfos;
+
+ friend struct MediaCodecList;
+};
+
+/**
+ * This interface is to be used by `MediaCodecList` to fill its members with
+ * appropriate information. `buildMediaCodecList()` will be called from a
+ * `MediaCodecList` object during its construction.
+ */
+struct MediaCodecListBuilderBase {
+ /**
+ * Build the `MediaCodecList` via the given `MediaCodecListWriter` interface.
+ *
+ * @param writer The writer interface.
+ * @return The status of the construction. `NO_ERROR` means success.
+ */
+ virtual status_t buildMediaCodecList(MediaCodecListWriter* writer) = 0;
+
+ /**
+ * The default destructor does nothing.
+ */
+ virtual ~MediaCodecListBuilderBase() = default;
+
+ typedef MediaCodecListBuilderBase *(*CreateBuilderFunc)(void);
+};
+
+} // namespace android
+
+#endif // MEDIA_CODEC_LIST_WRITER_H_
+
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index 3af2218..d5a8080 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -23,7 +23,7 @@
namespace android {
struct ABuffer;
-bool MakeAVCCodecSpecificData(MetaDataBase &meta, const sp<ABuffer> &accessUnit);
+bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 5e5ef6e..54a7095 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -64,11 +64,15 @@
status_t setMediaCas(const HInterfaceToken &casToken);
+ void disconnect();
+
size_t countTracks() const;
status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
status_t getFileFormat(sp<AMessage> *format) const;
+ status_t getExifOffsetSize(off64_t *offset, size_t *size) const;
+
status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
diff --git a/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
index 1b4d873..28f6094 100644
--- a/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
+++ b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
@@ -25,6 +25,7 @@
class OmxInfoBuilder : public MediaCodecListBuilderBase {
public:
OmxInfoBuilder();
+ ~OmxInfoBuilder() override = default;
status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
};
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 090d4e1..0fa9fcb 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -634,7 +634,7 @@
if (mFormat == NULL) {
mFormat = new MetaData;
- if (!MakeAVCCodecSpecificData(*mFormat, accessUnit)) {
+ if (!MakeAVCCodecSpecificData(*mFormat, accessUnit->data(), accessUnit->size())) {
mFormat.clear();
}
}
@@ -1010,7 +1010,7 @@
}
if (mFormat == NULL) {
mFormat = new MetaData;
- if (!MakeAVCCodecSpecificData(*mFormat, mBuffer)) {
+ if (!MakeAVCCodecSpecificData(*mFormat, mBuffer->data(), mBuffer->size())) {
ALOGW("Creating dummy AVC format for scrambled content");
mFormat = new MetaData;
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
@@ -1172,7 +1172,9 @@
if (mFormat == NULL) {
mFormat = new MetaData;
- if (!MakeAVCCodecSpecificData(*mFormat, accessUnit)) {
+ if (!MakeAVCCodecSpecificData(*mFormat,
+ accessUnit->data(),
+ accessUnit->size())) {
mFormat.clear();
}
}
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index f597e02..f7b569d 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -163,6 +163,8 @@
"audio_decoder.ac3", "audio_encoder.ac3" },
{ MEDIA_MIMETYPE_AUDIO_EAC3,
"audio_decoder.eac3", "audio_encoder.eac3" },
+ { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
+ "image_decoder.heic", "image_encoder.heic" },
};
static const size_t kNumMimeToRole =
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 8ef7620..cd0f75c 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -563,6 +563,10 @@
DescribeColorAspectsParams* colorAspectsParams =
(DescribeColorAspectsParams *)params;
+ if (!isValidOMXParam(colorAspectsParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadParameter;
}
@@ -584,6 +588,10 @@
DescribeHDRStaticInfoParams* hdrStaticInfoParams =
(DescribeHDRStaticInfoParams *)params;
+ if (!isValidOMXParam(hdrStaticInfoParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadPortIndex;
}
@@ -635,15 +643,17 @@
const DescribeHDRStaticInfoParams* hdrStaticInfoParams =
(DescribeHDRStaticInfoParams *)params;
+ if (!isValidOMXParam(hdrStaticInfoParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadPortIndex;
}
- if (hdrStaticInfoParams != NULL) {
- mOutputFormat = OMX_COLOR_FormatYUV420Planar16;
- mHdrStaticInfo = hdrStaticInfoParams->sInfo;
- updatePortDefinitions(false);
- }
+ mOutputFormat = OMX_COLOR_FormatYUV420Planar16;
+ mHdrStaticInfo = hdrStaticInfoParams->sInfo;
+ updatePortDefinitions(false);
return OMX_ErrorNone;
}
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index c65bdd0..fd14b18 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -32,8 +32,7 @@
virtual int sendEvent(mtp_event me) = 0;
// Return 0 if operation is successful, or -1 else
- virtual int start() = 0;
- virtual int configure(bool ptp) = 0;
+ virtual int start(bool ptp) = 0;
virtual void close() = 0;
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
index d9b6060..4a336c8 100644
--- a/media/mtp/MtpDescriptors.cpp
+++ b/media/mtp/MtpDescriptors.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
+#include <sys/types.h>
+
#include "MtpDescriptors.h"
namespace android {
@@ -257,4 +260,24 @@
.hs_descs = ptp_hs_descriptors,
};
+bool writeDescriptors(int fd, bool ptp) {
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd,
+ &(ptp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+ if (ret < 0) {
+ PLOG(ERROR) << fd << "Switching to V1 descriptor format";
+ ret = TEMP_FAILURE_RETRY(write(fd,
+ &(ptp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+ if (ret < 0) {
+ PLOG(ERROR) << fd << "Writing descriptors failed";
+ return false;
+ }
+ }
+ ret = TEMP_FAILURE_RETRY(write(fd, &mtp_strings, sizeof(mtp_strings)));
+ if (ret < 0) {
+ PLOG(ERROR) << fd << "Writing strings failed";
+ return false;
+ }
+ return true;
+}
+
}; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
index cfc3930..d600a24 100644
--- a/media/mtp/MtpDescriptors.h
+++ b/media/mtp/MtpDescriptors.h
@@ -23,6 +23,16 @@
namespace android {
+constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
+constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
+constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
+constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
+
+constexpr char FFS_PTP_EP0[] = "/dev/usb-ffs/ptp/ep0";
+constexpr char FFS_PTP_EP_IN[] = "/dev/usb-ffs/ptp/ep1";
+constexpr char FFS_PTP_EP_OUT[] = "/dev/usb-ffs/ptp/ep2";
+constexpr char FFS_PTP_EP_INTR[] = "/dev/usb-ffs/ptp/ep3";
+
constexpr int MAX_PACKET_SIZE_FS = 64;
constexpr int MAX_PACKET_SIZE_HS = 512;
constexpr int MAX_PACKET_SIZE_SS = 1024;
@@ -91,6 +101,8 @@
extern const struct desc_v1 ptp_desc_v1;
extern const struct functionfs_strings mtp_strings;
+bool writeDescriptors(int fd, bool ptp);
+
}; // namespace android
#endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpDevHandle.cpp b/media/mtp/MtpDevHandle.cpp
index 6aa57ac..e8bdf80 100644
--- a/media/mtp/MtpDevHandle.cpp
+++ b/media/mtp/MtpDevHandle.cpp
@@ -60,7 +60,7 @@
return ioctl(mFd, MTP_SEND_EVENT, reinterpret_cast<unsigned long>(&me));
}
-int MtpDevHandle::start() {
+int MtpDevHandle::start(bool /* ptp */) {
mFd.reset(TEMP_FAILURE_RETRY(open(mtp_dev_path, O_RDWR)));
if (mFd == -1) return -1;
return 0;
@@ -70,9 +70,4 @@
mFd.reset();
}
-int MtpDevHandle::configure(bool) {
- // Nothing to do, driver can configure itself
- return 0;
-}
-
} // namespace android
diff --git a/media/mtp/MtpDevHandle.h b/media/mtp/MtpDevHandle.h
index b0480ed..740ac85 100644
--- a/media/mtp/MtpDevHandle.h
+++ b/media/mtp/MtpDevHandle.h
@@ -36,10 +36,8 @@
int sendFile(mtp_file_range mfr);
int sendEvent(mtp_event me);
- int start();
+ int start(bool ptp);
void close();
-
- int configure(bool ptp);
};
} // namespace android
diff --git a/media/mtp/MtpFfsCompatHandle.cpp b/media/mtp/MtpFfsCompatHandle.cpp
index 3dd73f3..d2b342c 100644
--- a/media/mtp/MtpFfsCompatHandle.cpp
+++ b/media/mtp/MtpFfsCompatHandle.cpp
@@ -61,7 +61,8 @@
namespace android {
-MtpFfsCompatHandle::MtpFfsCompatHandle() :
+MtpFfsCompatHandle::MtpFfsCompatHandle(int controlFd) :
+ MtpFfsHandle(controlFd),
mMaxWrite(USB_FFS_MAX_WRITE),
mMaxRead(USB_FFS_MAX_READ) {}
@@ -108,10 +109,8 @@
return ret;
}
-int MtpFfsCompatHandle::start() {
- mLock.lock();
-
- if (!openEndpoints())
+int MtpFfsCompatHandle::start(bool ptp) {
+ if (!openEndpoints(ptp))
return -1;
for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
diff --git a/media/mtp/MtpFfsCompatHandle.h b/media/mtp/MtpFfsCompatHandle.h
index cd61482..5982d60 100644
--- a/media/mtp/MtpFfsCompatHandle.h
+++ b/media/mtp/MtpFfsCompatHandle.h
@@ -42,9 +42,9 @@
* Open ffs endpoints and allocate necessary kernel and user memory.
* Will sleep until endpoints are enabled, for up to 1 second.
*/
- int start() override;
+ int start(bool ptp) override;
- MtpFfsCompatHandle();
+ MtpFfsCompatHandle(int controlFd);
~MtpFfsCompatHandle();
};
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 217e0c9..952b907 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -39,10 +39,6 @@
namespace {
-constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
-constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
-constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
-
constexpr unsigned AIO_BUFS_MAX = 128;
constexpr unsigned AIO_BUF_LEN = 16384;
@@ -73,7 +69,9 @@
}
}
-MtpFfsHandle::MtpFfsHandle() {}
+MtpFfsHandle::MtpFfsHandle(int controlFd) {
+ mControl.reset(controlFd);
+}
MtpFfsHandle::~MtpFfsHandle() {}
@@ -83,27 +81,27 @@
mBulkOut.reset();
}
-bool MtpFfsHandle::openEndpoints() {
+bool MtpFfsHandle::openEndpoints(bool ptp) {
if (mBulkIn < 0) {
- mBulkIn.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_IN, O_RDWR)));
+ mBulkIn.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN, O_RDWR)));
if (mBulkIn < 0) {
- PLOG(ERROR) << FFS_MTP_EP_IN << ": cannot open bulk in ep";
+ PLOG(ERROR) << (ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN) << ": cannot open bulk in ep";
return false;
}
}
if (mBulkOut < 0) {
- mBulkOut.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_OUT, O_RDWR)));
+ mBulkOut.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT, O_RDWR)));
if (mBulkOut < 0) {
- PLOG(ERROR) << FFS_MTP_EP_OUT << ": cannot open bulk out ep";
+ PLOG(ERROR) << (ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT) << ": cannot open bulk out ep";
return false;
}
}
if (mIntr < 0) {
- mIntr.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_INTR, O_RDWR)));
+ mIntr.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR, O_RDWR)));
if (mIntr < 0) {
- PLOG(ERROR) << FFS_MTP_EP_INTR << ": cannot open intr ep";
+ PLOG(ERROR) << (ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR) << ": cannot open intr ep";
return false;
}
}
@@ -121,39 +119,8 @@
PLOG(ERROR) << "Failed to fadvise";
}
-bool MtpFfsHandle::initFunctionfs() {
- if (mControl < 0) { // might have already done this before
- mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
- if (mControl < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
- return false;
- }
- if (!writeDescriptors()) {
- closeConfig();
- return false;
- }
- }
- return true;
-}
-
-bool MtpFfsHandle::writeDescriptors() {
- ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
- &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
- ret = TEMP_FAILURE_RETRY(::write(mControl,
- &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
- return false;
- }
- }
- ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
- return false;
- }
- return true;
+bool MtpFfsHandle::writeDescriptors(bool ptp) {
+ return ::android::writeDescriptors(mControl, ptp);
}
void MtpFfsHandle::closeConfig() {
@@ -197,11 +164,9 @@
switch (event->type) {
case FUNCTIONFS_BIND:
case FUNCTIONFS_ENABLE:
- case FUNCTIONFS_RESUME:
ret = 0;
errno = 0;
break;
- case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_UNBIND:
case FUNCTIONFS_DISABLE:
errno = ESHUTDOWN;
@@ -211,6 +176,9 @@
if (handleControlRequest(&event->u.setup) == -1)
ret = -1;
break;
+ case FUNCTIONFS_SUSPEND:
+ case FUNCTIONFS_RESUME:
+ break;
default:
LOG(ERROR) << "Mtp Event " << event->type << " (unknown)";
}
@@ -277,10 +245,8 @@
return 0;
}
-int MtpFfsHandle::start() {
- mLock.lock();
-
- if (!openEndpoints())
+int MtpFfsHandle::start(bool ptp) {
+ if (!openEndpoints(ptp))
return -1;
for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
@@ -309,33 +275,10 @@
return 0;
}
-int MtpFfsHandle::configure(bool usePtp) {
- // Wait till previous server invocation has closed
- if (!mLock.try_lock_for(std::chrono::milliseconds(300))) {
- LOG(ERROR) << "MtpServer was unable to get configure lock";
- return -1;
- }
- int ret = 0;
-
- // If ptp is changed, the configuration must be rewritten
- if (mPtp != usePtp) {
- closeEndpoints();
- closeConfig();
- }
- mPtp = usePtp;
-
- if (!initFunctionfs()) {
- ret = -1;
- }
-
- mLock.unlock();
- return ret;
-}
-
void MtpFfsHandle::close() {
io_destroy(mCtx);
closeEndpoints();
- mLock.unlock();
+ closeConfig();
}
int MtpFfsHandle::waitEvents(struct io_buffer *buf, int min_events, struct io_event *events,
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2347000..24a8bd5 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -29,8 +29,6 @@
namespace android {
-constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
-
constexpr int NUM_IO_BUFS = 2;
struct io_buffer {
@@ -42,14 +40,10 @@
};
template <class T> class MtpFfsHandleTest;
-template <class T> class MtpFfsHandleTest_testControl_Test;
class MtpFfsHandle : public IMtpHandle {
template <class T> friend class MtpFfsHandleTest;
- template <class T> friend class MtpFfsHandleTest_testControl_Test;
protected:
- bool initFunctionfs();
- bool writeDescriptors();
void closeConfig();
void closeEndpoints();
void advise(int fd);
@@ -58,15 +52,12 @@
int handleEvent();
void cancelTransaction();
void doSendEvent(mtp_event me);
- bool openEndpoints();
+ bool openEndpoints(bool ptp);
static int getPacketSize(int ffs_fd);
- bool mPtp;
bool mCanceled;
- std::timed_mutex mLock; // protects configure() vs main loop
-
android::base::unique_fd mControl;
// "in" from the host's perspective => sink for mtp server
android::base::unique_fd mBulkIn;
@@ -99,12 +90,12 @@
int sendFile(mtp_file_range mfr) override;
int sendEvent(mtp_event me) override;
- int start() override;
+ int start(bool ptp) override;
void close() override;
- int configure(bool ptp) override;
+ bool writeDescriptors(bool ptp);
- MtpFfsHandle();
+ MtpFfsHandle(int controlFd);
~MtpFfsHandle();
};
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index cfda0a6..e4ac8b0 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -33,6 +33,7 @@
#include "MtpDebug.h"
#include "IMtpDatabase.h"
+#include "MtpDescriptors.h"
#include "MtpDevHandle.h"
#include "MtpFfsCompatHandle.h"
#include "MtpFfsHandle.h"
@@ -100,7 +101,7 @@
MTP_EVENT_DEVICE_PROP_CHANGED,
};
-MtpServer::MtpServer(IMtpDatabase* database, bool ptp,
+MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
@@ -118,30 +119,18 @@
mSendObjectFileSize(0),
mSendObjectModifiedTime(0)
{
+ bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
+ if (ffs_ok) {
+ bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
+ mHandle = aio_compat ? new MtpFfsCompatHandle(controlFd) : new MtpFfsHandle(controlFd);
+ } else {
+ mHandle = new MtpDevHandle();
+ }
}
MtpServer::~MtpServer() {
}
-IMtpHandle* MtpServer::sHandle = nullptr;
-
-int MtpServer::configure(bool usePtp) {
- bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
- if (sHandle == nullptr) {
- if (ffs_ok) {
- bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
- sHandle = aio_compat ? new MtpFfsCompatHandle() : new MtpFfsHandle();
- } else {
- sHandle = new MtpDevHandle();
- }
- }
-
- int ret = sHandle->configure(usePtp);
- if (ret) ALOGE("Failed to configure MTP driver!");
- android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
- return ret;
-}
-
void MtpServer::addStorage(MtpStorage* storage) {
Mutex::Autolock autoLock(mMutex);
@@ -175,19 +164,14 @@
}
void MtpServer::run() {
- if (!sHandle) {
- ALOGE("MtpServer was never configured!");
- return;
- }
-
- if (sHandle->start()) {
+ if (mHandle->start(mPtp)) {
ALOGE("Failed to start usb driver!");
- sHandle->close();
+ mHandle->close();
return;
}
while (1) {
- int ret = mRequest.read(sHandle);
+ int ret = mRequest.read(mHandle);
if (ret < 0) {
ALOGE("request read returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@@ -206,7 +190,7 @@
|| operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
|| operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
if (dataIn) {
- int ret = mData.read(sHandle);
+ int ret = mData.read(mHandle);
if (ret < 0) {
ALOGE("data read returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@@ -225,7 +209,7 @@
mData.setOperationCode(operation);
mData.setTransactionID(transaction);
ALOGV("sending data:");
- ret = mData.write(sHandle);
+ ret = mData.write(mHandle);
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@@ -238,7 +222,7 @@
mResponse.setTransactionID(transaction);
ALOGV("sending response %04X", mResponse.getResponseCode());
- ret = mResponse.write(sHandle);
+ ret = mResponse.write(mHandle);
const int savedErrno = errno;
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
@@ -262,7 +246,7 @@
}
mObjectEditList.clear();
- sHandle->close();
+ mHandle->close();
}
void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -295,7 +279,7 @@
mEvent.setEventCode(code);
mEvent.setTransactionID(mRequest.getTransactionID());
mEvent.setParameter(1, param1);
- if (mEvent.write(sHandle))
+ if (mEvent.write(mHandle))
ALOGE("Mtp send event failed: %s", strerror(errno));
}
}
@@ -806,7 +790,7 @@
mfr.transaction_id = mRequest.getTransactionID();
// then transfer the file
- int ret = sHandle->sendFile(mfr);
+ int ret = mHandle->sendFile(mfr);
if (ret < 0) {
ALOGE("Mtp send file got error %s", strerror(errno));
if (errno == ECANCELED) {
@@ -839,7 +823,7 @@
// send data
mData.setOperationCode(mRequest.getOperationCode());
mData.setTransactionID(mRequest.getTransactionID());
- mData.writeData(sHandle, thumb, thumbSize);
+ mData.writeData(mHandle, thumb, thumbSize);
free(thumb);
return MTP_RESPONSE_OK;
} else {
@@ -894,7 +878,7 @@
mResponse.setParameter(1, length);
// transfer the file
- int ret = sHandle->sendFile(mfr);
+ int ret = mHandle->sendFile(mfr);
ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
result = MTP_RESPONSE_OK;
if (ret < 0) {
@@ -1176,7 +1160,7 @@
}
// read the header, and possibly some data
- ret = mData.read(sHandle);
+ ret = mData.read(mHandle);
if (ret < MTP_CONTAINER_HEADER_SIZE) {
result = MTP_RESPONSE_GENERAL_ERROR;
goto done;
@@ -1224,7 +1208,7 @@
mfr.transaction_id = 0;
// transfer the file
- ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+ ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
if ((ret < 0) && (errno == ECANCELED)) {
isCanceled = true;
@@ -1353,7 +1337,7 @@
ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
// read the header, and possibly some data
- int ret = mData.read(sHandle);
+ int ret = mData.read(mHandle);
if (ret < MTP_CONTAINER_HEADER_SIZE)
return MTP_RESPONSE_GENERAL_ERROR;
int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
@@ -1376,7 +1360,7 @@
mfr.transaction_id = 0;
// transfer the file
- ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+ ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
if ((ret < 0) && (errno == ECANCELED)) {
isCanceled = true;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index af371eb..e633c52 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -65,7 +65,7 @@
MtpStorageList mStorages;
- static IMtpHandle* sHandle;
+ IMtpHandle* mHandle;
// handle for new object, set by SendObjectInfo and used by SendObject
MtpObjectHandle mSendObjectHandle;
@@ -98,7 +98,7 @@
Vector<ObjectEdit*> mObjectEditList;
public:
- MtpServer(IMtpDatabase* database, bool ptp,
+ MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
@@ -111,7 +111,6 @@
void addStorage(MtpStorage* storage);
void removeStorage(MtpStorage* storage);
- static int configure(bool usePtp);
void run();
void sendObjectAdded(MtpObjectHandle handle);
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 9c916b7..2174893 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -64,7 +64,7 @@
MtpFfsHandleTest() {
int fd[2];
- handle = std::make_unique<T>();
+ handle = std::make_unique<T>(-1);
EXPECT_EQ(pipe(fd), 0);
control.reset(fd[0]);
@@ -84,7 +84,7 @@
intr.reset(fd[0]);
handle->mIntr.reset(fd[1]);
- EXPECT_EQ(handle->start(), 0);
+ EXPECT_EQ(handle->start(false), 0);
}
~MtpFfsHandleTest() {
@@ -95,8 +95,8 @@
typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
-TYPED_TEST(MtpFfsHandleTest, testControl) {
- EXPECT_TRUE(this->handle->writeDescriptors());
+TYPED_TEST(MtpFfsHandleTest, testMtpControl) {
+ EXPECT_TRUE(this->handle->writeDescriptors(false));
struct desc_v2 desc;
struct functionfs_strings strings;
EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
@@ -105,6 +105,16 @@
EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
}
+TYPED_TEST(MtpFfsHandleTest, testPtpControl) {
+ EXPECT_TRUE(this->handle->writeDescriptors(true));
+ struct desc_v2 desc;
+ struct functionfs_strings strings;
+ EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+ EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+ EXPECT_TRUE(std::memcmp(&desc, &ptp_desc_v2, sizeof(desc)) == 0);
+ EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
TYPED_TEST(MtpFfsHandleTest, testRead) {
EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
char buf[TEST_PACKET_SIZE + 1];
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index ac837a3..b5e60a4 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -475,5 +475,11 @@
return AMEDIA_OK;
}
+EXPORT
+media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) {
+ ex->mImpl->disconnect();
+ return AMEDIA_OK;
+}
+
} // extern "C"
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 9bf450c..f32b83e 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -296,10 +296,8 @@
EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
-EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLS = "grid-cols";
-EXPORT const char* AMEDIAFORMAT_KEY_GRID_HEIGHT = "grid-height";
+EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
-EXPORT const char* AMEDIAFORMAT_KEY_GRID_WIDTH = "grid-width";
EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
@@ -329,6 +327,8 @@
EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
+EXPORT const char* AMEDIAFORMAT_KEY_TILE_HEIGHT = "tile-height";
+EXPORT const char* AMEDIAFORMAT_KEY_TILE_WIDTH = "tile-width";
EXPORT const char* AMEDIAFORMAT_KEY_TIME_US = "timeUs";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index f7b9cfd..1d295e4 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -216,6 +216,12 @@
#endif /* __ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+
+media_status_t AMediaExtractor_disconnect(AMediaExtractor *ex);
+
+#endif /* __ANDROID_API__ >= 29 */
+
#endif /* __ANDROID_API__ >= 21 */
__END_DECLS
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 1da9197..687054e 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -110,10 +110,8 @@
extern const char* AMEDIAFORMAT_KEY_DURATION;
extern const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL;
extern const char* AMEDIAFORMAT_KEY_FRAME_RATE;
-extern const char* AMEDIAFORMAT_KEY_GRID_COLS;
-extern const char* AMEDIAFORMAT_KEY_GRID_HEIGHT;
+extern const char* AMEDIAFORMAT_KEY_GRID_COLUMNS;
extern const char* AMEDIAFORMAT_KEY_GRID_ROWS;
-extern const char* AMEDIAFORMAT_KEY_GRID_WIDTH;
extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO;
extern const char* AMEDIAFORMAT_KEY_HEIGHT;
extern const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD;
@@ -143,6 +141,8 @@
extern const char* AMEDIAFORMAT_KEY_STRIDE;
extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID;
extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING;
+extern const char* AMEDIAFORMAT_KEY_TILE_HEIGHT;
+extern const char* AMEDIAFORMAT_KEY_TILE_WIDTH;
extern const char* AMEDIAFORMAT_KEY_TIME_US;
extern const char* AMEDIAFORMAT_KEY_TRACK_ID;
extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX;
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index 19e4b24..b0d8e7d 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -19,7 +19,7 @@
ifneq ($(TARGET_BUILD_PDK),true)
# Build MediaComponents only if this is not a PDK build. MediaComponents won't
# build in PDK builds because frameworks/base/core/java is not available but
-# IMediaSession2.aidl and IMediaSession2Callback.aidl are using classes from
+# IMediaSession2.aidl and IMediaController2.aidl are using classes from
# frameworks/base/core/java.
include $(CLEAR_VARS)
diff --git a/packages/MediaComponents/proguard.cfg b/packages/MediaComponents/proguard.cfg
index 43f2e63..d7bf730 100644
--- a/packages/MediaComponents/proguard.cfg
+++ b/packages/MediaComponents/proguard.cfg
@@ -16,5 +16,5 @@
# Keep entry point for updatable Java classes
-keep public class com.android.media.update.ApiFactory {
- public static java.lang.Object initialize(android.content.res.Resources, android.content.res.Resources$Theme);
+ public static com.android.media.update.ApiFactory initialize(android.content.pm.ApplicationInfo);
}
diff --git a/packages/MediaComponents/res/drawable/custom_progress.xml b/packages/MediaComponents/res/drawable/custom_progress.xml
new file mode 100644
index 0000000..9731a6e
--- /dev/null
+++ b/packages/MediaComponents/res/drawable/custom_progress.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2018 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:id="@android:id/background">
+ <shape android:shape="rectangle" >
+ <solid android:color="#26000000" />
+ </shape>
+ </item>
+ <item android:id="@android:id/secondaryProgress">
+ <clip>
+ <shape android:shape="rectangle" >
+ <solid android:color="#5Cffffff" />
+ </shape>
+ </clip>
+ </item>
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape android:shape="rectangle" >
+ <solid android:color="#ffffff" />
+ </shape>
+ </clip>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/drawable/custom_progress_thumb.xml b/packages/MediaComponents/res/drawable/custom_progress_thumb.xml
new file mode 100644
index 0000000..2e247f2
--- /dev/null
+++ b/packages/MediaComponents/res/drawable/custom_progress_thumb.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2018 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval" >
+ <solid android:color="#ffffff" />
+ <size
+ android:height="12dp"
+ android:width="12dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/drawable/ic_high_quality.xml b/packages/MediaComponents/res/drawable/ic_high_quality.xml
index e27d3e2..f76e22f 100644
--- a/packages/MediaComponents/res/drawable/ic_high_quality.xml
+++ b/packages/MediaComponents/res/drawable/ic_high_quality.xml
@@ -1,9 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="34dp"
+ android:height="34dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="#FFFFFF"
- android:pathData="M19,4L5,4c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM11,15L9.5,15v-2h-2v2L6,15L6,9h1.5v2.5h2L9.5,9L11,9v6zM18,14c0,0.55 -0.45,1 -1,1h-0.75v1.5h-1.5L14.75,15L14,15c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h3c0.55,0 1,0.45 1,1v4zM14.5,13.5h2v-3h-2v3z"/>
+ android:pathData="M19 4H5c-1.11 0-2 0.9-2 2v12c0 1.1 0.89 2 2 2h14c1.1 0 2-0.9 2-2V6c0-1.1-0.9-2-2-2zm-8 11H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 0.55-0.45 1-1 1h-0.75v1.5h-1.5V15H14c-0.55 0-1-0.45-1-1v-4c0-0.55 0.45 -1 1-1h3c0.55 0 1 0.45 1 1v4zm-3.5-0.5h2v-3h-2v3z" />
</vector>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/drawable/ic_replay_circle_filled.xml b/packages/MediaComponents/res/drawable/ic_replay_circle_filled.xml
index 389396b..a56d5d9 100644
--- a/packages/MediaComponents/res/drawable/ic_replay_circle_filled.xml
+++ b/packages/MediaComponents/res/drawable/ic_replay_circle_filled.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="40dp"
+ android:height="40dp"
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/packages/MediaComponents/res/drawable/ic_closed_caption_off.xml b/packages/MediaComponents/res/drawable/ic_subtitle_off.xml
similarity index 75%
rename from packages/MediaComponents/res/drawable/ic_closed_caption_off.xml
rename to packages/MediaComponents/res/drawable/ic_subtitle_off.xml
index a79cd11..c0a727a 100644
--- a/packages/MediaComponents/res/drawable/ic_closed_caption_off.xml
+++ b/packages/MediaComponents/res/drawable/ic_subtitle_off.xml
@@ -9,8 +9,7 @@
android:pathData="M0,0h24v24H0V0z" />
<path
android:fillColor="#FFFFFF"
- android:pathData="M19,5.5c0.27,0,0.5,0.23,0.5,0.5v12c0,0.27-0.23,0.5-0.5,0.5H5c-0.28,0-0.5-0.22-0.5-0.5V6c0-0.28,0.22-0.5,0.5-0.5H19
-M19,4H5C3.89,4,3,4.9,3,6v12c0,1.1,0.89,2,2,2h14c1.1,0,2-0.9,2-2V6C21,4.9,20.1,4,19,4L19,4z" />
+ android:pathData="M19.5,5.5v13h-15v-13H19.5z M19,4H5C3.89,4,3,4.9,3,6v12c0,1.1,0.89,2,2,2h14c1.1,0,2-0.9,2-2V6C21,4.9,20.1,4,19,4L19,4z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M11,11H9.5v-0.5h-2v3h2V13H11v1c0,0.55-0.45,1-1,1H7c-0.55,0-1-0.45-1-1v-4c0-0.55,0.45-1,1-1h3c0.55,0,1,0.45,1,1V11z" />
diff --git a/packages/MediaComponents/res/drawable/ic_subtitle_on.xml b/packages/MediaComponents/res/drawable/ic_subtitle_on.xml
new file mode 100644
index 0000000..7c91c06
--- /dev/null
+++ b/packages/MediaComponents/res/drawable/ic_subtitle_on.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19 4H5c-1.11 0-2 0.9-2 2v12c0 1.1 0.89 2 2 2h14c1.1 0 2-0.9 2-2V6c0-1.1-0.9-2-2-2zm-8 7H9.5v-0.5h-2v3h2V13H11v1c0 0.55-0.45 1-1 1H7c-0.55 0-1-0.45-1-1v-4c0-0.55 0.45 -1 1-1h3c0.55 0 1 0.45 1 1v1zm7 0h-1.5v-0.5h-2v3h2V13H18v1c0 0.55-0.45 1-1 1h-3c-0.55 0-1-0.45-1-1v-4c0-0.55 0.45 -1 1-1h3c0.55 0 1 0.45 1 1v1z" />
+</vector>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/embedded_settings_list_item.xml b/packages/MediaComponents/res/layout/embedded_settings_list_item.xml
new file mode 100644
index 0000000..1156dca
--- /dev/null
+++ b/packages/MediaComponents/res/layout/embedded_settings_list_item.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:orientation="horizontal"
+ android:background="@color/black_opacity_70">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/mcv2_embedded_settings_icon_size"
+ android:layout_height="@dimen/mcv2_embedded_settings_icon_size"
+ android:layout_margin="8dp"
+ android:gravity="center" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/main_text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_text_height"
+ android:gravity="center"
+ android:paddingLeft="2dp"
+ android:textColor="@color/white"
+ android:textSize="@dimen/mcv2_embedded_settings_main_text_size"/>
+
+ <TextView
+ android:id="@+id/sub_text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_text_height"
+ android:layout_below="@id/main_text"
+ android:gravity="center"
+ android:paddingLeft="2dp"
+ android:textColor="@color/white_opacity_70"
+ android:textSize="@dimen/mcv2_embedded_settings_sub_text_size"/>
+ </RelativeLayout>
+</LinearLayout>
+
diff --git a/packages/MediaComponents/res/layout/embedded_sub_settings_list_item.xml b/packages/MediaComponents/res/layout/embedded_sub_settings_list_item.xml
new file mode 100644
index 0000000..5947a72
--- /dev/null
+++ b/packages/MediaComponents/res/layout/embedded_sub_settings_list_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:orientation="horizontal"
+ android:background="@color/black_opacity_70">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/check"
+ android:layout_width="@dimen/mcv2_embedded_settings_icon_size"
+ android:layout_height="@dimen/mcv2_embedded_settings_icon_size"
+ android:layout_margin="8dp"
+ android:gravity="center"
+ android:src="@drawable/ic_check"/>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_embedded_settings_text_height"
+ android:gravity="center"
+ android:paddingLeft="2dp"
+ android:textColor="@color/white"
+ android:textSize="@dimen/mcv2_embedded_settings_main_text_size"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/packages/MediaComponents/res/layout/embedded_transport_controls.xml b/packages/MediaComponents/res/layout/embedded_transport_controls.xml
new file mode 100644
index 0000000..a3a5957
--- /dev/null
+++ b/packages/MediaComponents/res/layout/embedded_transport_controls.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/mcv2_transport_controls_padding"
+ android:paddingRight="@dimen/mcv2_transport_controls_padding"
+ android:visibility="visible">
+
+ <ImageButton android:id="@+id/prev" style="@style/EmbeddedTransportControlsButton.Previous" />
+ <ImageButton android:id="@+id/rew" style="@style/EmbeddedTransportControlsButton.Rew" />
+ <ImageButton android:id="@+id/pause" style="@style/EmbeddedTransportControlsButton.Pause" />
+ <ImageButton android:id="@+id/ffwd" style="@style/EmbeddedTransportControlsButton.Ffwd" />
+ <ImageButton android:id="@+id/next" style="@style/EmbeddedTransportControlsButton.Next" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/full_settings_list_item.xml b/packages/MediaComponents/res/layout/full_settings_list_item.xml
new file mode 100644
index 0000000..f92ea5e
--- /dev/null
+++ b/packages/MediaComponents/res/layout/full_settings_list_item.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:orientation="horizontal"
+ android:background="@color/black_opacity_70">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/mcv2_full_settings_icon_size"
+ android:layout_height="@dimen/mcv2_full_settings_icon_size"
+ android:layout_margin="8dp"
+ android:gravity="center"/>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/main_text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_text_height"
+ android:paddingLeft="2dp"
+ android:gravity="center"
+ android:textColor="@color/white"
+ android:textSize="@dimen/mcv2_full_settings_main_text_size"/>
+
+ <TextView
+ android:id="@+id/sub_text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_text_height"
+ android:layout_below="@id/main_text"
+ android:gravity="center"
+ android:paddingLeft="2dp"
+ android:textColor="@color/white_opacity_70"
+ android:textSize="@dimen/mcv2_full_settings_sub_text_size"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/packages/MediaComponents/res/layout/full_sub_settings_list_item.xml b/packages/MediaComponents/res/layout/full_sub_settings_list_item.xml
new file mode 100644
index 0000000..49128d0
--- /dev/null
+++ b/packages/MediaComponents/res/layout/full_sub_settings_list_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:orientation="horizontal"
+ android:background="@color/black_opacity_70">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/check"
+ android:layout_width="@dimen/mcv2_full_settings_icon_size"
+ android:layout_height="@dimen/mcv2_full_settings_icon_size"
+ android:layout_margin="8dp"
+ android:gravity="center"
+ android:src="@drawable/ic_check"/>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_height"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/mcv2_full_settings_text_height"
+ android:gravity="center"
+ android:paddingLeft="2dp"
+ android:textColor="@color/white"
+ android:textSize="@dimen/mcv2_full_settings_main_text_size"/>
+ </RelativeLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/full_transport_controls.xml b/packages/MediaComponents/res/layout/full_transport_controls.xml
new file mode 100644
index 0000000..0914785
--- /dev/null
+++ b/packages/MediaComponents/res/layout/full_transport_controls.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/mcv2_transport_controls_padding"
+ android:paddingRight="@dimen/mcv2_transport_controls_padding"
+ android:visibility="visible">
+
+ <ImageButton android:id="@+id/prev" style="@style/FullTransportControlsButton.Previous" />
+ <ImageButton android:id="@+id/rew" style="@style/FullTransportControlsButton.Rew" />
+ <ImageButton android:id="@+id/pause" style="@style/FullTransportControlsButton.Pause" />
+ <ImageButton android:id="@+id/ffwd" style="@style/FullTransportControlsButton.Ffwd" />
+ <ImageButton android:id="@+id/next" style="@style/FullTransportControlsButton.Next" />
+</LinearLayout>
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index 8488c84..dfda840 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -105,137 +105,134 @@
android:id="@+id/cast"
android:layout_centerVertical="true"
android:visibility="gone"
+ android:contentDescription="@string/mr_button_content_description"
style="@style/TitleBarButton" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
+ android:id="@+id/center_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:gravity="center"
- android:paddingTop="4dp"
- android:orientation="horizontal">
-
- <ImageButton android:id="@+id/prev" style="@style/TransportControlsButton.Previous" />
- <ImageButton android:id="@+id/rew" style="@style/TransportControlsButton.Rew" />
- <ImageButton android:id="@+id/pause" style="@style/TransportControlsButton.Pause" />
- <ImageButton android:id="@+id/ffwd" style="@style/TransportControlsButton.Ffwd" />
- <ImageButton android:id="@+id/next" style="@style/TransportControlsButton.Next" />
-
+ android:gravity="center">
</LinearLayout>
<SeekBar
android:id="@+id/mediacontroller_progress"
+ android:contentDescription="@string/mcv2_seek_bar_desc"
android:layout_width="match_parent"
- android:layout_height="32dp"
- android:padding="0dp"
- android:progressTint="#FFFFFFFF"
- android:thumbTint="#FFFFFFFF"/>
+ android:layout_height="12dp"
+ android:maxHeight="2dp"
+ android:minHeight="2dp"
+ android:padding="0dp"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="44dp"
- android:paddingLeft="15dp"
android:orientation="horizontal">
- <TextView
- android:id="@+id/time_current"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:paddingEnd="4dp"
- android:paddingStart="4dp"
- android:textSize="14sp"
- android:textStyle="bold"
- android:textColor="#FFFFFF" />
-
- <TextView
- android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@id/time_current"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:textSize="14sp"
- android:textStyle="bold"
- android:textColor="#BBBBBB" />
-
- <TextView
- android:id="@+id/ad_skip_time"
- android:gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:textSize="12sp"
- android:textColor="#FFFFFF"
- android:visibility="gone" />
-
<LinearLayout
- android:id="@+id/basic_controls"
- android:gravity="center"
- android:layout_alignParentRight="true"
+ android:id="@+id/bottom_bar_left"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:orientation="horizontal" >
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true">
<TextView
- android:id="@+id/ad_remaining"
+ android:id="@+id/ad_skip_time"
android:gravity="center"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="4dp"
android:textSize="12sp"
android:textColor="#FFFFFF"
android:visibility="gone" />
-
- <ImageButton
- android:id="@+id/mute"
- style="@style/BottomBarButton.Mute" />
- <ImageButton
- android:id="@+id/subtitle"
- android:scaleType="fitCenter"
- style="@style/BottomBarButton.CC" />
- <ImageButton
- android:id="@+id/fullscreen"
- style="@style/BottomBarButton.FullScreen"/>
- <ImageButton
- android:id="@+id/overflow_right"
- style="@style/BottomBarButton.OverflowRight"/>
</LinearLayout>
<LinearLayout
- android:id="@+id/extra_controls"
- android:layout_alignParentRight="true"
+ android:id="@+id/time"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:visibility="gone"
- android:orientation="horizontal"
- android:gravity="center">
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/bottom_bar_left"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:gravity="center" >
- <LinearLayout
- android:id="@+id/custom_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <ImageButton
- android:id="@+id/aspect_ratio"
- style="@style/BottomBarButton.AspectRatio" />
- <ImageButton
- android:id="@+id/video_quality"
- style="@style/BottomBarButton.VideoQuality" />
- <ImageButton
- android:id="@+id/settings"
- style="@style/BottomBarButton.Settings" />
- <ImageButton
- android:id="@+id/overflow_left"
- style="@style/BottomBarButton.OverflowLeft"/>
+ <TextView
+ android:id="@+id/time_current"
+ style="@style/TimeText.Current"/>
+ <TextView
+ android:id="@+id/time_interpunct"
+ style="@style/TimeText.Interpunct"/>
+ <TextView
+ android:id="@+id/time_end"
+ style="@style/TimeText.End"/>
</LinearLayout>
+ <LinearLayout
+ android:id="@+id/bottom_bar_right"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:gravity="right">
+
+ <LinearLayout
+ android:id="@+id/basic_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/ad_remaining"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="12sp"
+ android:textColor="#FFFFFF"
+ android:visibility="gone" />
+
+ <ImageButton
+ android:id="@+id/mute"
+ style="@style/BottomBarButton.Mute" />
+ <ImageButton
+ android:id="@+id/subtitle"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ style="@style/BottomBarButton.CC" />
+ <ImageButton
+ android:id="@+id/fullscreen"
+ style="@style/BottomBarButton.FullScreen"/>
+ <ImageButton
+ android:id="@+id/overflow_right"
+ style="@style/BottomBarButton.OverflowRight"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/extra_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+
+ <LinearLayout
+ android:id="@+id/custom_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:id="@+id/video_quality"
+ style="@style/BottomBarButton.VideoQuality" />
+ <ImageButton
+ android:id="@+id/settings"
+ style="@style/BottomBarButton.Settings" />
+ <ImageButton
+ android:id="@+id/overflow_left"
+ style="@style/BottomBarButton.OverflowLeft"/>
+ </LinearLayout>
+ </LinearLayout>
</RelativeLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/MediaComponents/res/layout/minimal_transport_controls.xml b/packages/MediaComponents/res/layout/minimal_transport_controls.xml
new file mode 100644
index 0000000..9ca3721
--- /dev/null
+++ b/packages/MediaComponents/res/layout/minimal_transport_controls.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:visibility="visible">
+
+ <ImageButton android:id="@+id/pause" style="@style/MinimalTransportControlsButton.Pause" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/settings_list.xml b/packages/MediaComponents/res/layout/settings_list.xml
index 37a3a60..ea30538 100644
--- a/packages/MediaComponents/res/layout/settings_list.xml
+++ b/packages/MediaComponents/res/layout/settings_list.xml
@@ -15,8 +15,8 @@
-->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/MediaControlView2_settings_width"
- android:layout_height="@dimen/MediaControlView2_settings_height"
+ android:layout_width="@dimen/mcv2_embedded_settings_width"
+ android:layout_height="@dimen/mcv2_embedded_settings_height"
android:divider="@null"
android:dividerHeight="0dp">
</ListView>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/settings_list_item.xml b/packages/MediaComponents/res/layout/settings_list_item.xml
deleted file mode 100644
index e7522b7..0000000
--- a/packages/MediaComponents/res/layout/settings_list_item.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/MediaControlView2_settings_width"
- android:layout_height="@dimen/MediaControlView2_settings_height"
- android:orientation="horizontal"
- android:background="@color/black_transparent_70">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="@dimen/MediaControlView2_settings_height"
- android:paddingRight="2dp"
- android:gravity="center"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/check"
- android:layout_width="@dimen/MediaControlView2_settings_icon_size"
- android:layout_height="@dimen/MediaControlView2_settings_icon_size"
- android:gravity="center"
- android:paddingLeft="2dp"
- android:src="@drawable/ic_check"/>
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="@dimen/MediaControlView2_settings_icon_size"
- android:layout_height="@dimen/MediaControlView2_settings_icon_size"
- android:gravity="center"
- android:paddingLeft="2dp"/>
- </LinearLayout>
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="@dimen/MediaControlView2_settings_height"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/main_text"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/MediaControlView2_text_width"
- android:paddingLeft="2dp"
- android:textColor="@color/white"
- android:textSize="@dimen/MediaControlView2_settings_main_text_size"/>
-
- <TextView
- android:id="@+id/sub_text"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/MediaControlView2_text_width"
- android:layout_below="@id/main_text"
- android:paddingLeft="2dp"
- android:textColor="@color/white_transparent_70"
- android:textSize="@dimen/MediaControlView2_settings_sub_text_size"/>
- </RelativeLayout>
-
-</LinearLayout>
-
diff --git a/packages/MediaComponents/res/values/arrays.xml b/packages/MediaComponents/res/values/arrays.xml
new file mode 100644
index 0000000..1187320
--- /dev/null
+++ b/packages/MediaComponents/res/values/arrays.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<resources>
+ <integer-array name="speed_multiplied_by_100">
+ <item>25</item>
+ <item>50</item>
+ <item>75</item>
+ <item>100</item>
+ <item>125</item>
+ <item>150</item>
+ <item>200</item>
+ </integer-array>
+</resources>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/values/colors.xml b/packages/MediaComponents/res/values/colors.xml
index 8ba069c..6a65ef5 100644
--- a/packages/MediaComponents/res/values/colors.xml
+++ b/packages/MediaComponents/res/values/colors.xml
@@ -17,6 +17,6 @@
<resources>
<color name="gray">#808080</color>
<color name="white">#ffffff</color>
- <color name="white_transparent_70">#B3ffffff</color>
- <color name="black_transparent_70">#B3000000</color>
+ <color name="white_opacity_70">#B3ffffff</color>
+ <color name="black_opacity_70">#B3000000</color>
</resources>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/values/dimens.xml b/packages/MediaComponents/res/values/dimens.xml
index b5ef626..8d72d40 100644
--- a/packages/MediaComponents/res/values/dimens.xml
+++ b/packages/MediaComponents/res/values/dimens.xml
@@ -41,12 +41,26 @@
<!-- Group list fade out animation duration. -->
<integer name="mr_controller_volume_group_list_fade_out_duration_ms">200</integer>
- <dimen name="MediaControlView2_settings_width">200dp</dimen>
- <dimen name="MediaControlView2_settings_height">36dp</dimen>
- <dimen name="MediaControlView2_settings_icon_size">28dp</dimen>
- <dimen name="MediaControlView2_settings_offset">8dp</dimen>
- <dimen name="MediaControlView2_text_width">18dp</dimen>
+ <dimen name="mcv2_embedded_settings_width">150dp</dimen>
+ <dimen name="mcv2_embedded_settings_height">36dp</dimen>
+ <dimen name="mcv2_embedded_settings_icon_size">20dp</dimen>
+ <dimen name="mcv2_embedded_settings_text_height">18dp</dimen>
+ <dimen name="mcv2_embedded_settings_main_text_size">12sp</dimen>
+ <dimen name="mcv2_embedded_settings_sub_text_size">10sp</dimen>
+ <dimen name="mcv2_full_settings_width">225dp</dimen>
+ <dimen name="mcv2_full_settings_height">54dp</dimen>
+ <dimen name="mcv2_full_settings_icon_size">30dp</dimen>
+ <dimen name="mcv2_full_settings_text_height">27dp</dimen>
+ <dimen name="mcv2_full_settings_main_text_size">16sp</dimen>
+ <dimen name="mcv2_full_settings_sub_text_size">13sp</dimen>
+ <dimen name="mcv2_settings_offset">8dp</dimen>
- <dimen name="MediaControlView2_settings_main_text_size">12sp</dimen>
- <dimen name="MediaControlView2_settings_sub_text_size">10sp</dimen>
+ <dimen name="mcv2_transport_controls_padding">4dp</dimen>
+ <dimen name="mcv2_pause_icon_size">36dp</dimen>
+ <dimen name="mcv2_full_icon_size">28dp</dimen>
+ <dimen name="mcv2_embedded_icon_size">24dp</dimen>
+ <dimen name="mcv2_minimal_icon_size">24dp</dimen>
+ <dimen name="mcv2_icon_margin">10dp</dimen>
+
+ <!-- TODO: adjust bottom bar view -->
</resources>
diff --git a/packages/MediaComponents/res/values/strings.xml b/packages/MediaComponents/res/values/strings.xml
index 305cef4..aaceac8 100644
--- a/packages/MediaComponents/res/values/strings.xml
+++ b/packages/MediaComponents/res/values/strings.xml
@@ -84,10 +84,6 @@
<!-- Placeholder text indicating that the user is currently casting screen. [CHAR LIMIT=50] -->
<string name="mr_controller_casting_screen">Casting screen</string>
- <string name="lockscreen_pause_button_content_description">Pause</string>
- <string name="lockscreen_play_button_content_description">Play</string>
- <string name="lockscreen_replay_button_content_description">Replay</string>
-
<!-- Text for error alert when a video container is not valid for progressive download/playback. -->
<string name="VideoView2_error_text_invalid_progressive_playback">This video isn\'t valid for streaming to this device.</string>
<!-- Text for error alert when a video cannot be played. It can be used by any app. -->
@@ -111,15 +107,20 @@
<string name="MediaControlView2_audio_track_none_text">None</string>
<string name="MediaControlView2_video_quality_text">Video quality</string>
<string name="MediaControlView2_video_quality_auto_text">Auto</string>
- <string name="MediaControlView2_playback_speed_text">Playback speed</string>
- <string name="MediaControlView2_playback_speed_0_25x_text">0.25x</string>
- <string name="MediaControlView2_playback_speed_0_5x_text">0.5x</string>
- <string name="MediaControlView2_playback_speed_0_75x_text">0.75x</string>
- <string name="MediaControlView2_playback_speed_1x_text">Normal</string>
- <string name="MediaControlView2_playback_speed_1_25x_text">1.25x</string>
- <string name="MediaControlView2_playback_speed_1_5x_text">1.5x</string>
- <string name="MediaControlView2_playback_speed_2x_text">2x</string>
<string name="MediaControlView2_help_text">Help & feedback</string>
+ <string name="MediaControlView2_playback_speed_text">Playback speed</string>
+ <string-array name="MediaControlView2_playback_speeds">
+ <item>0.25x</item>
+ <item>0.5x</item>
+ <item>0.75x</item>
+ <item>Normal</item>
+ <item>1.25x</item>
+ <item>1.5x</item>
+ <item>2x</item>
+ </string-array>
+ <!-- Placeholder text for displaying time. Used to calculate which size layout to use. -->
+ <string name="MediaControlView2_time_placeholder">00:00:00</string>
+
<!-- Text for displaying subtitle track number. -->
<string name="MediaControlView2_subtitle_track_number_text">
Track <xliff:g id="track_number" example="1">%1$s</xliff:g>
@@ -128,4 +129,25 @@
<string name="MediaControlView2_audio_track_number_text">
Track <xliff:g id="audio_number" example="1">%1$s</xliff:g>
</string>
+
+ <!--Content Descriptions -->
+ <string name="mcv2_back_button_desc">Back</string>
+ <string name="mcv2_overflow_left_button_desc">See more buttons</string>
+ <string name="mcv2_overflow_right_button_desc">Back to previous button list</string>
+ <string name="mcv2_seek_bar_desc">Playback progress</string>
+ <string name="mcv2_settings_button_desc">Settings</string>
+ <string name="mcv2_video_quality_button_desc">Video Quality Selection</string>
+ <string name="mcv2_cc_is_on">Subtitle is on. Click to hide it.</string>
+ <string name="mcv2_cc_is_off">Subtitle is off. Click to show it.</string>
+ <string name="mcv2_replay_button_desc">Replay</string>
+ <string name="mcv2_play_button_desc">Play</string>
+ <string name="mcv2_pause_button_desc">Pause</string>
+ <string name="mcv2_previous_button_desc">Previous media</string>
+ <string name="mcv2_next_button_desc">Next media</string>
+ <string name="mcv2_rewind_button_desc">Rewind by 10 seconds</string>
+ <string name="mcv2_ffwd_button_desc">Go forward by 30 seconds</string>
+ <string name="mcv2_launch_button_desc">Launch Link</string>
+ <string name="mcv2_muted_button_desc">Muted. Click to unmute</string>
+ <string name="mcv2_unmuted_button_desc">Click to Mute</string>
+ <string name="mcv2_full_screen_button_desc">Full screen</string>
</resources>
diff --git a/packages/MediaComponents/res/values/style.xml b/packages/MediaComponents/res/values/style.xml
index 23c7bc9..0be04e6 100644
--- a/packages/MediaComponents/res/values/style.xml
+++ b/packages/MediaComponents/res/values/style.xml
@@ -1,29 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="TransportControlsButton">
+ <style name="FullTransportControlsButton">
<item name="android:background">@null</item>
- <item name="android:layout_width">70dp</item>
- <item name="android:layout_height">40dp</item>
+ <item name="android:layout_margin">@dimen/mcv2_icon_margin</item>
+ <item name="android:scaleType">fitXY</item>
</style>
- <style name="TransportControlsButton.Previous">
+ <style name="FullTransportControlsButton.Previous">
<item name="android:src">@drawable/ic_skip_previous</item>
+ <item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_previous_button_desc</item>
</style>
- <style name="TransportControlsButton.Next">
+ <style name="FullTransportControlsButton.Next">
<item name="android:src">@drawable/ic_skip_next</item>
+ <item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_next_button_desc</item>
</style>
- <style name="TransportControlsButton.Pause">
+ <style name="FullTransportControlsButton.Pause">
<item name="android:src">@drawable/ic_pause_circle_filled</item>
+ <item name="android:layout_width">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
</style>
- <style name="TransportControlsButton.Ffwd">
+ <style name="FullTransportControlsButton.Ffwd">
<item name="android:src">@drawable/ic_forward_30</item>
+ <item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_ffwd_button_desc</item>
</style>
- <style name="TransportControlsButton.Rew">
+ <style name="FullTransportControlsButton.Rew">
<item name="android:src">@drawable/ic_rewind_10</item>
+ <item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_rewind_button_desc</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton">
+ <item name="android:background">@null</item>
+ <item name="android:layout_margin">@dimen/mcv2_icon_margin</item>
+ <item name="android:scaleType">fitXY</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton.Previous">
+ <item name="android:src">@drawable/ic_skip_previous</item>
+ <item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_previous_button_desc</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton.Next">
+ <item name="android:src">@drawable/ic_skip_next</item>
+ <item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_next_button_desc</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton.Pause">
+ <item name="android:src">@drawable/ic_pause_circle_filled</item>
+ <item name="android:layout_width">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton.Ffwd">
+ <item name="android:src">@drawable/ic_forward_30</item>
+ <item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_ffwd_button_desc</item>
+ </style>
+
+ <style name="EmbeddedTransportControlsButton.Rew">
+ <item name="android:src">@drawable/ic_rewind_10</item>
+ <item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_rewind_button_desc</item>
+ </style>
+
+ <style name="MinimalTransportControlsButton">
+ <item name="android:background">@null</item>
+ <item name="android:scaleType">fitXY</item>
+ </style>
+
+ <style name="MinimalTransportControlsButton.Pause">
+ <item name="android:src">@drawable/ic_pause_circle_filled</item>
+ <item name="android:layout_width">@dimen/mcv2_minimal_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_minimal_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
</style>
<style name="TitleBar">
@@ -38,51 +106,80 @@
<style name="TitleBarButton.Back">
<item name="android:src">@drawable/ic_arrow_back</item>
+ <item name="android:contentDescription">@string/mcv2_back_button_desc</item>
</style>
<style name="TitleBarButton.Launch">
<item name="android:src">@drawable/ic_launch</item>
+ <item name="android:contentDescription">@string/mcv2_launch_button_desc</item>
+ </style>
+
+ <style name="TimeText">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingStart">4dp</item>
+ <item name="android:paddingEnd">4dp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="TimeText.Current">
+ <item name="android:textColor">@color/white</item>
+ <item name="android:text">@string/MediaControlView2_time_placeholder</item>
+ </style>
+
+ <style name="TimeText.Interpunct">
+ <item name="android:textColor">@color/white_opacity_70</item>
+ <item name="android:text">·</item>
+ </style>
+
+ <style name="TimeText.End">
+ <item name="android:textColor">@color/white_opacity_70</item>
+ <item name="android:text">@string/MediaControlView2_time_placeholder</item>
</style>
<style name="BottomBarButton">
<item name="android:background">@null</item>
- <item name="android:layout_width">44dp</item>
- <item name="android:layout_height">34dp</item>
- <item name="android:layout_marginTop">5dp</item>
- <item name="android:layout_marginBottom">5dp</item>
- <item name="android:paddingLeft">5dp</item>
- <item name="android:paddingRight">5dp</item>
+ <item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:layout_margin">@dimen/mcv2_icon_margin</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:scaleType">fitXY</item>
</style>
<style name="BottomBarButton.CC">
- <item name="android:src">@drawable/ic_media_subtitle_disabled</item>
+ <item name="android:src">@drawable/ic_subtitle_off</item>
+ <item name="android:contentDescription">@string/mcv2_cc_is_off</item>
</style>
<style name="BottomBarButton.FullScreen">
<item name="android:src">@drawable/ic_fullscreen</item>
+ <item name="android:contentDescription">@string/mcv2_full_screen_button_desc</item>
</style>
<style name="BottomBarButton.OverflowRight">
<item name="android:src">@drawable/ic_chevron_right</item>
+ <item name="android:contentDescription">@string/mcv2_overflow_right_button_desc</item>
</style>
<style name="BottomBarButton.OverflowLeft">
<item name="android:src">@drawable/ic_chevron_left</item>
+ <item name="android:contentDescription">@string/mcv2_overflow_left_button_desc</item>
</style>
<style name="BottomBarButton.Settings">
<item name="android:src">@drawable/ic_settings</item>
- </style>
-
- <style name="BottomBarButton.AspectRatio">
- <item name="android:src">@drawable/ic_aspect_ratio</item>
+ <item name="android:contentDescription">@string/mcv2_settings_button_desc</item>
</style>
<style name="BottomBarButton.Mute">
- <item name="android:src">@drawable/ic_mute</item>
+ <item name="android:src">@drawable/ic_unmute</item>
+ <item name="android:contentDescription">@string/mcv2_unmuted_button_desc</item>
</style>
<style name="BottomBarButton.VideoQuality">
- <item name="android:src">@drawable/ic_high_quality</item>
+ <item name="android:src">@drawable/ic_high_quality</item>
+ <item name="android:contentDescription">@string/mcv2_video_quality_button_desc</item>
</style>
</resources>
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaController2.aidl
similarity index 67%
rename from packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
rename to packages/MediaComponents/src/com/android/media/IMediaController2.aidl
index 3d812f8..0488b70 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaController2.aidl
@@ -23,21 +23,29 @@
import com.android.media.IMediaSession2;
/**
- * Interface from MediaSession2 to MediaSession2Record.
+ * Interface from MediaSession2 to MediaController2.
* <p>
* Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
* and holds calls from session to make session owner(s) frozen.
*/
-oneway interface IMediaSession2Callback {
- void onPlaybackStateChanged(in Bundle state);
- void onPlaylistChanged(in List<Bundle> playlist);
- void onPlaylistParamsChanged(in Bundle params);
+// TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
+// Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
+oneway interface IMediaController2 {
+ void onPlayerStateChanged(int state);
+ void onPositionChanged(long eventTimeMs, long positionMs);
+ void onPlaybackSpeedChanged(float speed);
+ void onBufferedPositionChanged(long bufferedPositionMs);
+ void onPlaylistChanged(in List<Bundle> playlist, in Bundle metadata);
+ void onPlaylistMetadataChanged(in Bundle metadata);
void onPlaybackInfoChanged(in Bundle playbackInfo);
+ void onRepeatModeChanged(int repeatMode);
+ void onShuffleModeChanged(int shuffleMode);
+ void onError(int errorCode, in Bundle extras);
- // TODO(jaewan): Handle when the playlist becomes too huge.
- void onConnected(IMediaSession2 sessionBinder, in Bundle commandGroup, in Bundle playbackState,
- in Bundle playbackInfo, in Bundle params, in List<Bundle> playlist,
- in PendingIntent sessionActivity);
+ void onConnected(IMediaSession2 sessionBinder, in Bundle commandGroup,
+ int playerState, long positionEventTimeMs, long positionMs, float playbackSpeed,
+ long bufferedPositionMs, in Bundle playbackInfo, int repeatMode, int shuffleMode,
+ in List<Bundle> playlist, in PendingIntent sessionActivity);
void onDisconnected();
void onCustomLayoutChanged(in List<Bundle> commandButtonlist);
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
index ef7120d..664467d 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
@@ -20,55 +20,66 @@
import android.os.ResultReceiver;
import android.net.Uri;
-import com.android.media.IMediaSession2Callback;
+import com.android.media.IMediaController2;
/**
- * Interface to MediaSession2.
+ * Interface from MediaController2 to MediaSession2.
* <p>
* Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
* and holds calls from session to make session owner(s) frozen.
*/
+ // TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
+ // Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
oneway interface IMediaSession2 {
// TODO(jaewan): add onCommand() to send private command
- // TODO(jaewan): Due to the nature of oneway calls, APIs can be called in out of order
- // Add id for individual calls to address this.
- // TODO(jaewan): We may consider to add another binder just for the connection
+ // TODO(jaewan): (Post P) We may consider to add another binder just for the connection
// not to expose other methods to the controller whose connection wasn't accepted.
// But this would be enough for now because it's the same as existing
// MediaBrowser and MediaBrowserService.
- void connect(IMediaSession2Callback caller, String callingPackage);
- void release(IMediaSession2Callback caller);
+ void connect(IMediaController2 caller, String callingPackage);
+ void release(IMediaController2 caller);
- void setVolumeTo(IMediaSession2Callback caller, int value, int flags);
- void adjustVolume(IMediaSession2Callback caller, int direction, int flags);
+ void setVolumeTo(IMediaController2 caller, int value, int flags);
+ void adjustVolume(IMediaController2 caller, int direction, int flags);
//////////////////////////////////////////////////////////////////////////////////////////////
// send command
//////////////////////////////////////////////////////////////////////////////////////////////
- void sendTransportControlCommand(IMediaSession2Callback caller,
+ void sendTransportControlCommand(IMediaController2 caller,
int commandCode, in Bundle args);
- void sendCustomCommand(IMediaSession2Callback caller, in Bundle command, in Bundle args,
+ void sendCustomCommand(IMediaController2 caller, in Bundle command, in Bundle args,
in ResultReceiver receiver);
- void prepareFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extras);
- void prepareFromSearch(IMediaSession2Callback caller, String query, in Bundle extras);
- void prepareFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extras);
- void playFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extras);
- void playFromSearch(IMediaSession2Callback caller, String query, in Bundle extras);
- void playFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extras);
- void setRating(IMediaSession2Callback caller, String mediaId, in Bundle rating);
+ void prepareFromUri(IMediaController2 caller, in Uri uri, in Bundle extras);
+ void prepareFromSearch(IMediaController2 caller, String query, in Bundle extras);
+ void prepareFromMediaId(IMediaController2 caller, String mediaId, in Bundle extras);
+ void playFromUri(IMediaController2 caller, in Uri uri, in Bundle extras);
+ void playFromSearch(IMediaController2 caller, String query, in Bundle extras);
+ void playFromMediaId(IMediaController2 caller, String mediaId, in Bundle extras);
+ void setRating(IMediaController2 caller, String mediaId, in Bundle rating);
+
+ void setPlaylist(IMediaController2 caller, in List<Bundle> playlist, in Bundle metadata);
+ void updatePlaylistMetadata(IMediaController2 caller, in Bundle metadata);
+ void addPlaylistItem(IMediaController2 caller, int index, in Bundle mediaItem);
+ void removePlaylistItem(IMediaController2 caller, in Bundle mediaItem);
+ void replacePlaylistItem(IMediaController2 caller, int index, in Bundle mediaItem);
+ void skipToPlaylistItem(IMediaController2 caller, in Bundle mediaItem);
+ void skipToPreviousItem(IMediaController2 caller);
+ void skipToNextItem(IMediaController2 caller);
+ void setRepeatMode(IMediaController2 caller, int repeatMode);
+ void setShuffleMode(IMediaController2 caller, int shuffleMode);
//////////////////////////////////////////////////////////////////////////////////////////////
// library service specific
//////////////////////////////////////////////////////////////////////////////////////////////
- void getLibraryRoot(IMediaSession2Callback caller, in Bundle rootHints);
- void getItem(IMediaSession2Callback caller, String mediaId);
- void getChildren(IMediaSession2Callback caller, String parentId, int page, int pageSize,
+ void getLibraryRoot(IMediaController2 caller, in Bundle rootHints);
+ void getItem(IMediaController2 caller, String mediaId);
+ void getChildren(IMediaController2 caller, String parentId, int page, int pageSize,
in Bundle extras);
- void search(IMediaSession2Callback caller, String query, in Bundle extras);
- void getSearchResult(IMediaSession2Callback caller, String query, int page, int pageSize,
+ void search(IMediaController2 caller, String query, in Bundle extras);
+ void getSearchResult(IMediaController2 caller, String query, int page, int pageSize,
in Bundle extras);
- void subscribe(IMediaSession2Callback caller, String parentId, in Bundle extras);
- void unsubscribe(IMediaSession2Callback caller, String parentId);
+ void subscribe(IMediaController2 caller, String parentId, in Bundle extras);
+ void unsubscribe(IMediaController2 caller, String parentId);
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 96fdda0..249365a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -16,7 +16,20 @@
package com.android.media;
-import static android.media.MediaSession2.*;
+import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -28,13 +41,13 @@
import android.media.MediaController2.ControllerCallback;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
-import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
+import android.media.MediaMetadata2;
+import android.media.MediaPlaylistAgent.RepeatMode;
+import android.media.MediaPlaylistAgent.ShuffleMode;
+import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
-import android.media.MediaSession2.PlaylistParams;
+import android.media.SessionCommandGroup2;
import android.media.MediaSessionService2;
-import android.media.PlaybackState2;
import android.media.Rating2;
import android.media.SessionToken2;
import android.media.update.MediaController2Provider;
@@ -61,7 +74,7 @@
private final Context mContext;
private final Object mLock = new Object();
- private final MediaSession2CallbackStub mSessionCallbackStub;
+ private final MediaController2Stub mControllerStub;
private final SessionToken2 mToken;
private final ControllerCallback mCallback;
private final Executor mCallbackExecutor;
@@ -72,17 +85,29 @@
@GuardedBy("mLock")
private boolean mIsReleased;
@GuardedBy("mLock")
- private PlaybackState2 mPlaybackState;
- @GuardedBy("mLock")
private List<MediaItem2> mPlaylist;
@GuardedBy("mLock")
- private PlaylistParams mPlaylistParams;
+ private MediaMetadata2 mPlaylistMetadata;
+ @GuardedBy("mLock")
+ private @RepeatMode int mRepeatMode;
+ @GuardedBy("mLock")
+ private @ShuffleMode int mShuffleMode;
+ @GuardedBy("mLock")
+ private int mPlayerState;
+ @GuardedBy("mLock")
+ private long mPositionEventTimeMs;
+ @GuardedBy("mLock")
+ private long mPositionMs;
+ @GuardedBy("mLock")
+ private float mPlaybackSpeed;
+ @GuardedBy("mLock")
+ private long mBufferedPositionMs;
@GuardedBy("mLock")
private PlaybackInfo mPlaybackInfo;
@GuardedBy("mLock")
private PendingIntent mSessionActivity;
@GuardedBy("mLock")
- private CommandGroup mAllowedCommands;
+ private SessionCommandGroup2 mAllowedCommands;
// Assignment should be used with the lock hold, but should be used without a lock to prevent
// potential deadlock.
@@ -110,7 +135,7 @@
throw new IllegalArgumentException("executor shouldn't be null");
}
mContext = context;
- mSessionCallbackStub = new MediaSession2CallbackStub(this);
+ mControllerStub = new MediaController2Stub(this);
mToken = token;
mCallback = callback;
mCallbackExecutor = executor;
@@ -191,7 +216,7 @@
private void connectToSession(IMediaSession2 sessionBinder) {
try {
- sessionBinder.connect(mSessionCallbackStub, mContext.getPackageName());
+ sessionBinder.connect(mControllerStub, mContext.getPackageName());
} catch (RemoteException e) {
Log.w(TAG, "Failed to call connection request. Framework will retry"
+ " automatically");
@@ -216,12 +241,12 @@
}
binder = mSessionBinder;
mSessionBinder = null;
- mSessionCallbackStub.destroy();
+ mControllerStub.destroy();
}
if (binder != null) {
try {
binder.asBinder().unlinkToDeath(mDeathRecipient, 0);
- binder.release(mSessionCallbackStub);
+ binder.release(mControllerStub);
} catch (RemoteException e) {
// No-op.
}
@@ -235,8 +260,8 @@
return mSessionBinder;
}
- MediaSession2CallbackStub getControllerStub() {
- return mSessionCallbackStub;
+ MediaController2Stub getControllerStub() {
+ return mControllerStub;
}
Executor getCallbackExecutor() {
@@ -271,7 +296,7 @@
}
// Returns session binder if the controller can send the command.
- IMediaSession2 getSessionBinderIfAble(Command command) {
+ IMediaSession2 getSessionBinderIfAble(SessionCommand2 command) {
synchronized (mLock) {
if (!mAllowedCommands.hasCommand(command)) {
Log.w(TAG, "Controller isn't allowed to call command, command=" + command);
@@ -300,27 +325,62 @@
@Override
public void play_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PLAY);
+ sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY);
}
@Override
public void pause_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE);
+ sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE);
}
@Override
public void stop_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_STOP);
+ sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_STOP);
+ }
+
+ @Override
+ public void skipToPlaylistItem_impl(MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ final IMediaSession2 binder = mSessionBinder;
+ if (binder != null) {
+ try {
+ binder.skipToPlaylistItem(mControllerStub, item.toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
public void skipToPreviousItem_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM);
+ final IMediaSession2 binder = mSessionBinder;
+ if (binder != null) {
+ try {
+ binder.skipToPreviousItem(mControllerStub);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
public void skipToNextItem_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM);
+ final IMediaSession2 binder = mSessionBinder;
+ if (binder != null) {
+ try {
+ binder.skipToNextItem(mControllerStub);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
private void sendTransportControlCommand(int commandCode) {
@@ -331,7 +391,7 @@
final IMediaSession2 binder = mSessionBinder;
if (binder != null) {
try {
- binder.sendTransportControlCommand(mSessionCallbackStub, commandCode, args);
+ binder.sendTransportControlCommand(mControllerStub, commandCode, args);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -340,9 +400,6 @@
}
}
- //////////////////////////////////////////////////////////////////////////////////////
- // TODO(jaewan): Implement follows
- //////////////////////////////////////////////////////////////////////////////////////
@Override
public PendingIntent getSessionActivity_impl() {
return mSessionActivity;
@@ -351,10 +408,10 @@
@Override
public void setVolumeTo_impl(int value, int flags) {
// TODO(hdmoon): sanity check
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYBACK_SET_VOLUME);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
if (binder != null) {
try {
- binder.setVolumeTo(mSessionCallbackStub, value, flags);
+ binder.setVolumeTo(mControllerStub, value, flags);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -366,10 +423,10 @@
@Override
public void adjustVolume_impl(int direction, int flags) {
// TODO(hdmoon): sanity check
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYBACK_SET_VOLUME);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
if (binder != null) {
try {
- binder.adjustVolume(mSessionCallbackStub, direction, flags);
+ binder.adjustVolume(mControllerStub, direction, flags);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -380,13 +437,13 @@
@Override
public void prepareFromUri_impl(Uri uri, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_URI);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PREPARE_FROM_URI);
if (uri == null) {
throw new IllegalArgumentException("uri shouldn't be null");
}
if (binder != null) {
try {
- binder.prepareFromUri(mSessionCallbackStub, uri, extras);
+ binder.prepareFromUri(mControllerStub, uri, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -397,13 +454,14 @@
@Override
public void prepareFromSearch_impl(String query, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_SEARCH);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH);
if (TextUtils.isEmpty(query)) {
throw new IllegalArgumentException("query shouldn't be empty");
}
if (binder != null) {
try {
- binder.prepareFromSearch(mSessionCallbackStub, query, extras);
+ binder.prepareFromSearch(mControllerStub, query, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -414,13 +472,14 @@
@Override
public void prepareFromMediaId_impl(String mediaId, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_MEDIA_ID);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID);
if (mediaId == null) {
throw new IllegalArgumentException("mediaId shouldn't be null");
}
if (binder != null) {
try {
- binder.prepareFromMediaId(mSessionCallbackStub, mediaId, extras);
+ binder.prepareFromMediaId(mControllerStub, mediaId, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -431,13 +490,13 @@
@Override
public void playFromUri_impl(Uri uri, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_URI);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_URI);
if (uri == null) {
throw new IllegalArgumentException("uri shouldn't be null");
}
if (binder != null) {
try {
- binder.playFromUri(mSessionCallbackStub, uri, extras);
+ binder.playFromUri(mControllerStub, uri, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -448,13 +507,13 @@
@Override
public void playFromSearch_impl(String query, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_SEARCH);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH);
if (TextUtils.isEmpty(query)) {
throw new IllegalArgumentException("query shouldn't be empty");
}
if (binder != null) {
try {
- binder.playFromSearch(mSessionCallbackStub, query, extras);
+ binder.playFromSearch(mControllerStub, query, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -465,13 +524,14 @@
@Override
public void playFromMediaId_impl(String mediaId, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_MEDIA_ID);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID);
if (mediaId == null) {
throw new IllegalArgumentException("mediaId shouldn't be null");
}
if (binder != null) {
try {
- binder.playFromMediaId(mSessionCallbackStub, mediaId, extras);
+ binder.playFromMediaId(mControllerStub, mediaId, extras);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -492,7 +552,7 @@
final IMediaSession2 binder = mSessionBinder;
if (binder != null) {
try {
- binder.setRating(mSessionCallbackStub, mediaId, rating.toBundle());
+ binder.setRating(mControllerStub, mediaId, rating.toBundle());
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -502,14 +562,14 @@
}
@Override
- public void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb) {
+ public void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
final IMediaSession2 binder = getSessionBinderIfAble(command);
if (binder != null) {
try {
- binder.sendCustomCommand(mSessionCallbackStub, command.toBundle(), args, cb);
+ binder.sendCustomCommand(mControllerStub, command.toBundle(), args, cb);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -526,18 +586,65 @@
}
@Override
+ public void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata) {
+ if (list == null) {
+ throw new IllegalArgumentException("list shouldn't be null");
+ }
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_LIST);
+ if (binder != null) {
+ List<Bundle> bundleList = new ArrayList<>();
+ for (int i = 0; i < list.size(); i++) {
+ bundleList.add(list.get(i).toBundle());
+ }
+ Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
+ try {
+ binder.setPlaylist(mControllerStub, bundleList, metadataBundle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
+ }
+
+ @Override
+ public MediaMetadata2 getPlaylistMetadata_impl() {
+ synchronized (mLock) {
+ return mPlaylistMetadata;
+ }
+ }
+
+ @Override
+ public void updatePlaylistMetadata_impl(MediaMetadata2 metadata) {
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_PLAYLIST_SET_LIST_METADATA);
+ if (binder != null) {
+ Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
+ try {
+ binder.updatePlaylistMetadata(mControllerStub, metadataBundle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
+ }
+
+ @Override
public void prepare_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE);
+ sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE);
}
@Override
public void fastForward_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_FAST_FORWARD);
+ // TODO(jaewan): Implement this. Note that fast forward isn't a transport command anymore
+ //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_FAST_FORWARD);
}
@Override
public void rewind_impl() {
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_REWIND);
+ // TODO(jaewan): Implement this. Note that rewind isn't a transport command anymore
+ //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_REWIND);
}
@Override
@@ -547,65 +654,102 @@
}
Bundle args = new Bundle();
args.putLong(MediaSession2Stub.ARGUMENT_KEY_POSITION, pos);
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SEEK_TO, args);
- }
-
- @Override
- public void skipToPlaylistItem_impl(MediaItem2 item) {
- if (item == null) {
- throw new IllegalArgumentException("item shouldn't be null");
- }
-
- // TODO(jaewan): Implement this
- /*
- Bundle args = new Bundle();
- args.putInt(MediaSession2Stub.ARGUMENT_KEY_ITEM_INDEX, item);
- sendTransportControlCommand(
- MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM, args);
- */
- }
-
- @Override
- public PlaybackState2 getPlaybackState_impl() {
- synchronized (mLock) {
- return mPlaybackState;
- }
+ sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO, args);
}
@Override
public void addPlaylistItem_impl(int index, MediaItem2 item) {
- // TODO(jaewan): Implement (b/73149584)
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_ADD_ITEM);
+ if (binder != null) {
+ try {
+ binder.addPlaylistItem(mControllerStub, index, item.toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
public void removePlaylistItem_impl(MediaItem2 item) {
- // TODO(jaewan): Implement (b/73149584)
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REMOVE_ITEM);
+ if (binder != null) {
+ try {
+ binder.removePlaylistItem(mControllerStub, item.toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
public void replacePlaylistItem_impl(int index, MediaItem2 item) {
- // TODO: Implement this (b/73149407)
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REPLACE_ITEM);
+ if (binder != null) {
+ try {
+ binder.replacePlaylistItem(mControllerStub, index, item.toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
- public PlaylistParams getPlaylistParams_impl() {
- synchronized (mLock) {
- return mPlaylistParams;
+ public int getShuffleMode_impl() {
+ return mShuffleMode;
+ }
+
+ @Override
+ public void setShuffleMode_impl(int shuffleMode) {
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE);
+ if (binder != null) {
+ try {
+ binder.setShuffleMode(mControllerStub, shuffleMode);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
+ }
+
+ @Override
+ public int getRepeatMode_impl() {
+ return mRepeatMode;
+ }
+
+ @Override
+ public void setRepeatMode_impl(int repeatMode) {
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE);
+ if (binder != null) {
+ try {
+ binder.setRepeatMode(mControllerStub, repeatMode);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
}
}
@@ -617,37 +761,33 @@
}
@Override
- public void setPlaylistParams_impl(PlaylistParams params) {
- if (params == null) {
- throw new IllegalArgumentException("params shouldn't be null");
- }
- Bundle args = new Bundle();
- args.putBundle(MediaSession2Stub.ARGUMENT_KEY_PLAYLIST_PARAMS, params.toBundle());
- sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS, args);
- }
-
- @Override
public int getPlayerState_impl() {
- // TODO(jaewan): Implement
- return 0;
+ synchronized (mLock) {
+ return mPlayerState;
+ }
}
@Override
- public long getPosition_impl() {
- // TODO(jaewan): Implement
- return 0;
+ public long getCurrentPosition_impl() {
+ synchronized (mLock) {
+ long timeDiff = System.currentTimeMillis() - mPositionEventTimeMs;
+ long expectedPosition = mPositionMs + (long) (mPlaybackSpeed * timeDiff);
+ return Math.max(0, expectedPosition);
+ }
}
@Override
public float getPlaybackSpeed_impl() {
- // TODO(jaewan): Implement
- return 0;
+ synchronized (mLock) {
+ return mPlaybackSpeed;
+ }
}
@Override
public long getBufferedPosition_impl() {
- // TODO(jaewan): Implement
- return 0;
+ synchronized (mLock) {
+ return mBufferedPositionMs;
+ }
}
@Override
@@ -656,27 +796,54 @@
return null;
}
- void pushPlaybackStateChanges(final PlaybackState2 state) {
+ void pushPlayerStateChanges(final int state) {
synchronized (mLock) {
- mPlaybackState = state;
+ mPlayerState = state;
}
mCallbackExecutor.execute(() -> {
if (!mInstance.isConnected()) {
return;
}
- mCallback.onPlaybackStateChanged(mInstance, state);
+ mCallback.onPlayerStateChanged(mInstance, state);
});
}
- void pushPlaylistParamsChanges(final PlaylistParams params) {
+ // TODO(jaewan): Rename to seek completed
+ void pushPositionChanges(final long eventTimeMs, final long positionMs) {
synchronized (mLock) {
- mPlaylistParams = params;
+ mPositionEventTimeMs = eventTimeMs;
+ mPositionMs = positionMs;
}
mCallbackExecutor.execute(() -> {
if (!mInstance.isConnected()) {
return;
}
- mCallback.onPlaylistParamsChanged(mInstance, params);
+ mCallback.onSeekCompleted(mInstance, positionMs);
+ });
+ }
+
+ void pushPlaybackSpeedChanges(final float speed) {
+ synchronized (mLock) {
+ mPlaybackSpeed = speed;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onPlaybackSpeedChanged(mInstance, speed);
+ });
+ }
+
+ void pushBufferedPositionChanges(final long bufferedPositionMs) {
+ synchronized (mLock) {
+ mBufferedPositionMs = bufferedPositionMs;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ // TODO(jaewan): Fix this -- it's now buffered state
+ //mCallback.onBufferedPositionChanged(mInstance, bufferedPositionMs);
});
}
@@ -692,22 +859,76 @@
});
}
- void pushPlaylistChanges(final List<MediaItem2> playlist) {
+ void pushPlaylistChanges(final List<MediaItem2> playlist, final MediaMetadata2 metadata) {
synchronized (mLock) {
mPlaylist = playlist;
- mCallbackExecutor.execute(() -> {
- if (!mInstance.isConnected()) {
- return;
- }
- mCallback.onPlaylistChanged(mInstance, playlist);
- });
+ mPlaylistMetadata = metadata;
}
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onPlaylistChanged(mInstance, playlist, metadata);
+ });
+ }
+
+ void pushPlaylistMetadataChanges(MediaMetadata2 metadata) {
+ synchronized (mLock) {
+ mPlaylistMetadata = metadata;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onPlaylistMetadataChanged(mInstance, metadata);
+ });
+ }
+
+ void pushShuffleModeChanges(int shuffleMode) {
+ synchronized (mLock) {
+ mShuffleMode = shuffleMode;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onShuffleModeChanged(mInstance, shuffleMode);
+ });
+ }
+
+ void pushRepeatModeChanges(int repeatMode) {
+ synchronized (mLock) {
+ mRepeatMode = repeatMode;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onRepeatModeChanged(mInstance, repeatMode);
+ });
+ }
+
+ void pushError(int errorCode, Bundle extras) {
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onError(mInstance, errorCode, extras);
+ });
}
// Should be used without a lock to prevent potential deadlock.
void onConnectedNotLocked(IMediaSession2 sessionBinder,
- final CommandGroup allowedCommands, final PlaybackState2 state, final PlaybackInfo info,
- final PlaylistParams params, final List<MediaItem2> playlist,
+ final SessionCommandGroup2 allowedCommands,
+ final int playerState,
+ final long positionEventTimeMs,
+ final long positionMs,
+ final float playbackSpeed,
+ final long bufferedPositionMs,
+ final PlaybackInfo info,
+ final int repeatMode,
+ final int shuffleMode,
+ final List<MediaItem2> playlist,
final PendingIntent sessionActivity) {
if (DEBUG) {
Log.d(TAG, "onConnectedNotLocked sessionBinder=" + sessionBinder
@@ -731,9 +952,14 @@
return;
}
mAllowedCommands = allowedCommands;
- mPlaybackState = state;
+ mPlayerState = playerState;
+ mPositionEventTimeMs = positionEventTimeMs;
+ mPositionMs = positionMs;
+ mPlaybackSpeed = playbackSpeed;
+ mBufferedPositionMs = bufferedPositionMs;
mPlaybackInfo = info;
- mPlaylistParams = params;
+ mRepeatMode = repeatMode;
+ mShuffleMode = shuffleMode;
mPlaylist = playlist;
mSessionActivity = sessionActivity;
mSessionBinder = sessionBinder;
@@ -765,7 +991,7 @@
}
}
- void onCustomCommand(final Command command, final Bundle args,
+ void onCustomCommand(final SessionCommand2 command, final Bundle args,
final ResultReceiver receiver) {
if (DEBUG) {
Log.d(TAG, "onCustomCommand cmd=" + command);
@@ -776,7 +1002,7 @@
});
}
- void onAllowedCommandsChanged(final CommandGroup commands) {
+ void onAllowedCommandsChanged(final SessionCommandGroup2 commands) {
mCallbackExecutor.execute(() -> {
mCallback.onAllowedCommandsChanged(mInstance, commands);
});
@@ -838,7 +1064,6 @@
private static final String KEY_AUDIO_ATTRIBUTES =
"android.media.playbackinfo_impl.audio_attrs";
- private final Context mContext;
private final PlaybackInfo mInstance;
private final int mPlaybackType;
@@ -847,9 +1072,8 @@
private final int mCurrentVolume;
private final AudioAttributes mAudioAttrs;
- private PlaybackInfoImpl(Context context, int playbackType, AudioAttributes attrs,
- int controlType, int max, int current) {
- mContext = context;
+ private PlaybackInfoImpl(int playbackType, AudioAttributes attrs, int controlType,
+ int max, int current) {
mPlaybackType = playbackType;
mAudioAttrs = attrs;
mControlType = controlType;
@@ -883,11 +1107,11 @@
return mCurrentVolume;
}
- public PlaybackInfo getInstance() {
+ PlaybackInfo getInstance() {
return mInstance;
}
- public Bundle toBundle() {
+ Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
bundle.putInt(KEY_CONTROL_TYPE, mControlType);
@@ -897,13 +1121,13 @@
return bundle;
}
- public static PlaybackInfo createPlaybackInfo(Context context, int playbackType,
- AudioAttributes attrs, int controlType, int max, int current) {
- return new PlaybackInfoImpl(context, playbackType, attrs, controlType, max, current)
+ static PlaybackInfo createPlaybackInfo(int playbackType, AudioAttributes attrs,
+ int controlType, int max, int current) {
+ return new PlaybackInfoImpl(playbackType, attrs, controlType, max, current)
.getInstance();
}
- public static PlaybackInfo fromBundle(Context context, Bundle bundle) {
+ static PlaybackInfo fromBundle(Bundle bundle) {
if (bundle == null) {
return null;
}
@@ -913,8 +1137,7 @@
final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
- return createPlaybackInfo(
- context, volumeType, attrs, volumeControl, maxVolume, currentVolume);
+ return createPlaybackInfo(volumeType, attrs, volumeControl, maxVolume, currentVolume);
}
}
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
similarity index 71%
rename from packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
rename to packages/MediaComponents/src/com/android/media/MediaController2Stub.java
index 451368f..2cfc5df 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
@@ -20,11 +20,10 @@
import android.content.Context;
import android.media.MediaController2;
import android.media.MediaItem2;
-import android.media.MediaSession2.Command;
+import android.media.MediaMetadata2;
+import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
-import android.media.MediaSession2.PlaylistParams;
-import android.media.PlaybackState2;
+import android.media.SessionCommandGroup2;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.text.TextUtils;
@@ -37,13 +36,13 @@
import java.util.ArrayList;
import java.util.List;
-public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
- private static final String TAG = "MS2CallbackStub";
+public class MediaController2Stub extends IMediaController2.Stub {
+ private static final String TAG = "MediaController2Stub";
private static final boolean DEBUG = true; // TODO(jaewan): Change
private final WeakReference<MediaController2Impl> mController;
- MediaSession2CallbackStub(MediaController2Impl controller) {
+ MediaController2Stub(MediaController2Impl controller) {
mController = new WeakReference<>(controller);
}
@@ -68,7 +67,7 @@
}
@Override
- public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
+ public void onPlayerStateChanged(int state) {
final MediaController2Impl controller;
try {
controller = getController();
@@ -76,12 +75,59 @@
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- controller.pushPlaybackStateChanges(
- PlaybackState2.fromBundle(controller.getContext(), state));
+ controller.pushPlayerStateChanges(state);
}
@Override
- public void onPlaylistChanged(List<Bundle> playlistBundle) throws RuntimeException {
+ public void onPositionChanged(long eventTimeMs, long positionMs) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (eventTimeMs < 0) {
+ Log.w(TAG, "onPositionChanged(): Ignoring negative eventTimeMs");
+ return;
+ }
+ if (positionMs < 0) {
+ Log.w(TAG, "onPositionChanged(): Ignoring negative positionMs");
+ return;
+ }
+ controller.pushPositionChanges(eventTimeMs, positionMs);
+ }
+
+ @Override
+ public void onPlaybackSpeedChanged(float speed) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushPlaybackSpeedChanges(speed);
+ }
+
+ @Override
+ public void onBufferedPositionChanged(long bufferedPositionMs) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (bufferedPositionMs < 0) {
+ Log.w(TAG, "onBufferedPositionChanged(): Ignoring negative bufferedPositionMs");
+ return;
+ }
+ controller.pushBufferedPositionChanges(bufferedPositionMs);
+ }
+
+ @Override
+ public void onPlaylistChanged(List<Bundle> playlistBundle, Bundle metadataBundle) {
final MediaController2Impl controller;
try {
controller = getController();
@@ -90,23 +136,24 @@
return;
}
if (playlistBundle == null) {
- Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist");
+ Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist from " + controller);
return;
}
List<MediaItem2> playlist = new ArrayList<>();
for (Bundle bundle : playlistBundle) {
- MediaItem2 item = MediaItem2.fromBundle(controller.getContext(), bundle);
+ MediaItem2 item = MediaItem2.fromBundle(bundle);
if (item == null) {
Log.w(TAG, "onPlaylistChanged(): Ignoring null item in playlist");
} else {
playlist.add(item);
}
}
- controller.pushPlaylistChanges(playlist);
+ MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
+ controller.pushPlaylistChanges(playlist, metadata);
}
@Override
- public void onPlaylistParamsChanged(Bundle paramsBundle) throws RuntimeException {
+ public void onPlaylistMetadataChanged(Bundle metadataBundle) throws RuntimeException {
final MediaController2Impl controller;
try {
controller = getController();
@@ -114,12 +161,20 @@
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- PlaylistParams params = PlaylistParams.fromBundle(controller.getContext(), paramsBundle);
- if (params == null) {
- Log.w(TAG, "onPlaylistParamsChanged(): Ignoring null playlistParams");
+ MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
+ controller.pushPlaylistMetadataChanges(metadata);
+ }
+
+ @Override
+ public void onRepeatModeChanged(int repeatMode) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- controller.pushPlaylistParamsChanges(params);
+ controller.pushRepeatModeChanges(repeatMode);
}
@Override
@@ -134,20 +189,43 @@
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- MediaController2.PlaybackInfo info =
- PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo);
+ MediaController2.PlaybackInfo info = PlaybackInfoImpl.fromBundle(playbackInfo);
if (info == null) {
Log.w(TAG, "onPlaybackInfoChanged(): Ignoring null playbackInfo");
return;
}
- controller.pushPlaybackInfoChanges(
- PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+ controller.pushPlaybackInfoChanges(info);
+ }
+
+ @Override
+ public void onShuffleModeChanged(int shuffleMode) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushShuffleModeChanges(shuffleMode);
+ }
+
+ @Override
+ public void onError(int errorCode, Bundle extras) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushError(errorCode, extras);
}
@Override
public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
- Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
- itemBundleList, PendingIntent sessionActivity) {
+ int playerState, long positionEventTimeMs, long positionMs, float playbackSpeed,
+ long bufferedPositionMs, Bundle playbackInfo, int shuffleMode, int repeatMode,
+ List<Bundle> itemBundleList, PendingIntent sessionActivity) {
final MediaController2Impl controller = mController.get();
if (controller == null) {
if (DEBUG) {
@@ -160,17 +238,16 @@
if (itemBundleList != null) {
itemList = new ArrayList<>();
for (int i = 0; i < itemBundleList.size(); i++) {
- MediaItem2 item = MediaItem2.fromBundle(context, itemBundleList.get(i));
+ MediaItem2 item = MediaItem2.fromBundle(itemBundleList.get(i));
if (item != null) {
itemList.add(item);
}
}
}
controller.onConnectedNotLocked(sessionBinder,
- CommandGroup.fromBundle(context, commandGroup),
- PlaybackState2.fromBundle(context, playbackState),
- PlaybackInfoImpl.fromBundle(context, playbackInfo),
- PlaylistParams.fromBundle(context, playlistParams),
+ SessionCommandGroup2.fromBundle(commandGroup),
+ playerState, positionEventTimeMs, positionMs, playbackSpeed, bufferedPositionMs,
+ PlaybackInfoImpl.fromBundle(playbackInfo), repeatMode, shuffleMode,
itemList, sessionActivity);
}
@@ -205,8 +282,7 @@
}
List<CommandButton> layout = new ArrayList<>();
for (int i = 0; i < commandButtonlist.size(); i++) {
- CommandButton button = CommandButtonImpl.fromBundle(
- controller.getContext(), commandButtonlist.get(i));
+ CommandButton button = CommandButtonImpl.fromBundle(commandButtonlist.get(i));
if (button != null) {
layout.add(button);
}
@@ -227,7 +303,7 @@
// TODO(jaewan): Revisit here. Could be a bug
return;
}
- CommandGroup commands = CommandGroup.fromBundle(controller.getContext(), commandsBundle);
+ SessionCommandGroup2 commands = SessionCommandGroup2.fromBundle(commandsBundle);
if (commands == null) {
Log.w(TAG, "onAllowedCommandsChanged(): Ignoring null commands");
return;
@@ -244,7 +320,7 @@
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- Command command = Command.fromBundle(controller.getContext(), commandBundle);
+ SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
if (command == null) {
Log.w(TAG, "onCustomCommand(): Ignoring null command");
return;
@@ -290,8 +366,7 @@
// TODO(jaewan): Revisit here. Could be a bug
return;
}
- browser.onGetItemDone(mediaId,
- MediaItem2Impl.fromBundle(browser.getContext(), itemBundle));
+ browser.onGetItemDone(mediaId, MediaItem2.fromBundle(itemBundle));
}
@Override
@@ -317,7 +392,7 @@
if (itemBundleList != null) {
result = new ArrayList<>();
for (Bundle bundle : itemBundleList) {
- result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+ result.add(MediaItem2.fromBundle(bundle));
}
}
browser.onGetChildrenDone(parentId, page, pageSize, result, extras);
@@ -367,7 +442,7 @@
if (itemBundleList != null) {
result = new ArrayList<>();
for (Bundle bundle : itemBundleList) {
- result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+ result.add(MediaItem2.fromBundle(bundle));
}
}
browser.onGetSearchResultDone(query, page, pageSize, result, extras);
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
index 039ff8f..910a0f1 100644
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.media.DataSourceDesc;
import android.media.MediaItem2;
import android.media.MediaItem2.Builder;
@@ -31,21 +30,29 @@
import android.os.Bundle;
import android.text.TextUtils;
+import java.util.UUID;
+
public class MediaItem2Impl implements MediaItem2Provider {
private static final String KEY_ID = "android.media.mediaitem2.id";
private static final String KEY_FLAGS = "android.media.mediaitem2.flags";
private static final String KEY_METADATA = "android.media.mediaitem2.metadata";
+ private static final String KEY_UUID = "android.media.mediaitem2.uuid";
- private final Context mContext;
private final MediaItem2 mInstance;
private final String mId;
private final int mFlags;
+ private final UUID mUUID;
private MediaMetadata2 mMetadata;
private DataSourceDesc mDataSourceDesc;
// From the public API
- public MediaItem2Impl(@NonNull Context context, @NonNull String mediaId,
- @Nullable DataSourceDesc dsd, @Nullable MediaMetadata2 metadata, @Flags int flags) {
+ public MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
+ @Nullable MediaMetadata2 metadata, @Flags int flags) {
+ this(mediaId, dsd, metadata, flags, null);
+ }
+
+ private MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
+ @Nullable MediaMetadata2 metadata, @Flags int flags, @Nullable UUID uuid) {
if (mediaId == null) {
throw new IllegalArgumentException("mediaId shouldn't be null");
}
@@ -53,29 +60,22 @@
throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
}
- mContext = context;
mId = mediaId;
mDataSourceDesc = dsd;
mMetadata = metadata;
mFlags = flags;
+ mUUID = (uuid == null) ? UUID.randomUUID() : uuid;
mInstance = new MediaItem2(this);
}
- // Create anonymized version
- public MediaItem2Impl(Context context, String mediaId, MediaMetadata2 metadata,
- @Flags int flags) {
- if (mediaId == null) {
- throw new IllegalArgumentException("mediaId shouldn't be null");
+ @Override
+ public boolean equals_impl(Object obj) {
+ if (!(obj instanceof MediaItem2)) {
+ return false;
}
- if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
- throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
- }
- mContext = context;
- mId = mediaId;
- mMetadata = metadata;
- mFlags = flags;
- mInstance = new MediaItem2(this);
+ MediaItem2 other = (MediaItem2) obj;
+ return mUUID.equals(((MediaItem2Impl) other.getProvider()).mUUID);
}
/**
@@ -90,19 +90,42 @@
if (mMetadata != null) {
bundle.putBundle(KEY_METADATA, mMetadata.toBundle());
}
+ bundle.putString(KEY_UUID, mUUID.toString());
return bundle;
}
- public static MediaItem2 fromBundle(Context context, Bundle bundle) {
+ /**
+ * Create a MediaItem2 from the {@link Bundle}.
+ *
+ * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
+ * @return The newly created MediaItem2
+ */
+ public static MediaItem2 fromBundle_impl(@NonNull Bundle bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ final String uuidString = bundle.getString(KEY_UUID);
+ return fromBundle(bundle, UUID.fromString(uuidString));
+ }
+
+ /**
+ * Create a MediaItem2 from the {@link Bundle} with the specified {@link UUID}.
+ * If {@link UUID}
+ * can be null for creating new.
+ *
+ * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
+ * @param uuid A {@link UUID} to override. Can be {@link null} for override.
+ * @return The newly created MediaItem2
+ */
+ static MediaItem2 fromBundle(@NonNull Bundle bundle, @Nullable UUID uuid) {
if (bundle == null) {
return null;
}
final String id = bundle.getString(KEY_ID);
final Bundle metadataBundle = bundle.getBundle(KEY_METADATA);
- final MediaMetadata2 metadata = metadataBundle != null
- ? MediaMetadata2.fromBundle(context, metadataBundle) : null;
+ final MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
final int flags = bundle.getInt(KEY_FLAGS);
- return new MediaItem2Impl(context, id, metadata, flags).getInstance();
+ return new MediaItem2Impl(id, null, metadata, flags, uuid).getInstance();
}
private MediaItem2 getInstance() {
@@ -157,15 +180,13 @@
}
public static class BuilderImpl implements MediaItem2Provider.BuilderProvider {
- private Context mContext;
private Builder mInstance;
private @Flags int mFlags;
private String mMediaId;
private MediaMetadata2 mMetadata;
private DataSourceDesc mDataSourceDesc;
- public BuilderImpl(Context context, Builder instance, int flags) {
- mContext = context;
+ public BuilderImpl(Builder instance, int flags) {
mInstance = instance;
mFlags = flags;
}
@@ -196,8 +217,7 @@
// TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?)
id = (mMediaId != null) ? mMediaId : toString();
}
- return new MediaItem2Impl(mContext, id, mDataSourceDesc, mMetadata, mFlags)
- .getInstance();
+ return new MediaItem2Impl(id, mDataSourceDesc, mMetadata, mFlags).getInstance();
}
}
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index b3512cc..cf34cd4 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -151,8 +151,7 @@
private final String mRootId;
private final Bundle mExtras;
- public LibraryRootImpl(Context context, LibraryRoot instance, String rootId,
- Bundle extras) {
+ public LibraryRootImpl(LibraryRoot instance, String rootId, Bundle extras) {
if (rootId == null) {
throw new IllegalArgumentException("rootId shouldn't be null.");
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
index 333455d..cf1c532 100644
--- a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
@@ -19,7 +19,6 @@
import static android.media.MediaMetadata2.*;
import android.annotation.Nullable;
-import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaMetadata2;
import android.media.MediaMetadata2.BitmapKey;
@@ -78,8 +77,6 @@
METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG);
METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_FREQUENCY, METADATA_TYPE_FLOAT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_CALLSIGN, METADATA_TYPE_TEXT);
}
private static final @TextKey
@@ -107,12 +104,10 @@
METADATA_KEY_ALBUM_ART_URI
};
- private final Context mContext;
private final MediaMetadata2 mInstance;
private final Bundle mBundle;
- public MediaMetadata2Impl(Context context, Bundle bundle) {
- mContext = context;
+ public MediaMetadata2Impl(Bundle bundle) {
mInstance = new MediaMetadata2(this);
mBundle = bundle;
}
@@ -170,7 +165,7 @@
// TODO(jaewan): Add backward compatibility
Rating2 rating = null;
try {
- rating = Rating2.fromBundle(mContext, mBundle.getBundle(key));
+ rating = Rating2.fromBundle(mBundle.getBundle(key));
} catch (Exception e) {
// ignore, value was not a rating
Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -227,33 +222,28 @@
return mBundle;
}
- public static MediaMetadata2 fromBundle(Context context, Bundle bundle) {
- return new MediaMetadata2Impl(context, bundle).getInstance();
+ public static MediaMetadata2 fromBundle_impl(Bundle bundle) {
+ return (bundle == null) ? null : new MediaMetadata2Impl(bundle).getInstance();
}
public static final class BuilderImpl implements MediaMetadata2Provider.BuilderProvider {
- private final Context mContext;
private final MediaMetadata2.Builder mInstance;
private final Bundle mBundle;
- public BuilderImpl(Context context, MediaMetadata2.Builder instance) {
- mContext = context;
+ public BuilderImpl(MediaMetadata2.Builder instance) {
mInstance = instance;
mBundle = new Bundle();
}
- public BuilderImpl(Context context, MediaMetadata2.Builder instance,
- MediaMetadata2 source) {
+ public BuilderImpl(MediaMetadata2.Builder instance, MediaMetadata2 source) {
if (source == null) {
throw new IllegalArgumentException("source shouldn't be null");
}
- mContext = context;
mInstance = instance;
mBundle = new Bundle(source.toBundle());
}
- public BuilderImpl(Context context, int maxBitmapSize) {
- mContext = context;
+ public BuilderImpl(int maxBitmapSize) {
mInstance = new MediaMetadata2.Builder(this);
mBundle = new Bundle();
@@ -366,7 +356,7 @@
@Override
public MediaMetadata2 build_impl() {
- return new MediaMetadata2Impl(mContext, mBundle).getInstance();
+ return new MediaMetadata2Impl(mBundle).getInstance();
}
private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
diff --git a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java b/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
index bab29b7..dfd4e1a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
@@ -19,7 +19,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
+import android.media.DataSourceDesc;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaPlaylistAgent;
@@ -36,18 +36,17 @@
public class MediaPlaylistAgentImpl implements MediaPlaylistAgentProvider {
private static final String TAG = "MediaPlaylistAgent";
- private final Context mContext;
private final MediaPlaylistAgent mInstance;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final ArrayMap<PlaylistEventCallback, Executor> mCallbacks = new ArrayMap<>();
- public MediaPlaylistAgentImpl(Context context, MediaPlaylistAgent instance) {
- mContext = context;
+ public MediaPlaylistAgentImpl(MediaPlaylistAgent instance) {
mInstance = instance;
}
+ @Override
final public void registerPlaylistEventCallback_impl(
@NonNull @CallbackExecutor Executor executor, @NonNull PlaylistEventCallback callback) {
if (executor == null) {
@@ -66,6 +65,7 @@
}
}
+ @Override
final public void unregisterPlaylistEventCallback_impl(
@NonNull PlaylistEventCallback callback) {
if (callback == null) {
@@ -76,6 +76,7 @@
}
}
+ @Override
final public void notifyPlaylistChanged_impl() {
ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
List<MediaItem2> playlist= mInstance.getPlaylist();
@@ -88,6 +89,7 @@
}
}
+ @Override
final public void notifyPlaylistMetadataChanged_impl() {
ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
for (int i = 0; i < callbacks.size(); i++) {
@@ -98,6 +100,7 @@
}
}
+ @Override
final public void notifyShuffleModeChanged_impl() {
ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
for (int i = 0; i < callbacks.size(); i++) {
@@ -108,6 +111,7 @@
}
}
+ @Override
final public void notifyRepeatModeChanged_impl() {
ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
for (int i = 0; i < callbacks.size(); i++) {
@@ -118,66 +122,98 @@
}
}
+ @Override
public @Nullable List<MediaItem2> getPlaylist_impl() {
// empty implementation
return null;
}
+ @Override
public void setPlaylist_impl(@NonNull List<MediaItem2> list,
@Nullable MediaMetadata2 metadata) {
// empty implementation
}
+ @Override
public @Nullable MediaMetadata2 getPlaylistMetadata_impl() {
// empty implementation
return null;
}
+ @Override
public void updatePlaylistMetadata_impl(@Nullable MediaMetadata2 metadata) {
// empty implementation
}
+ @Override
public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) {
// empty implementation
}
+ @Override
public void removePlaylistItem_impl(@NonNull MediaItem2 item) {
// empty implementation
}
+ @Override
public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) {
// empty implementation
}
+ @Override
public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) {
// empty implementation
}
+ @Override
public void skipToPreviousItem_impl() {
// empty implementation
}
+ @Override
public void skipToNextItem_impl() {
// empty implementation
}
+ @Override
public int getRepeatMode_impl() {
return MediaPlaylistAgent.REPEAT_MODE_NONE;
}
+ @Override
public void setRepeatMode_impl(int repeatMode) {
// empty implementation
}
+ @Override
public int getShuffleMode_impl() {
// empty implementation
return MediaPlaylistAgent.SHUFFLE_MODE_NONE;
}
+ @Override
public void setShuffleMode_impl(int shuffleMode) {
// empty implementation
}
+ @Override
+ public @Nullable MediaItem2 getMediaItem_impl(@NonNull DataSourceDesc dsd) {
+ if (dsd == null) {
+ throw new IllegalArgumentException("dsd shouldn't be null");
+ }
+ List<MediaItem2> itemList = mInstance.getPlaylist();
+ if (itemList == null) {
+ return null;
+ }
+ for (int i = 0; i < itemList.size(); i++) {
+ MediaItem2 item = itemList.get(i);
+ if (item != null && item.getDataSourceDesc() == dsd) {
+ return item;
+ }
+ }
+ return null;
+ }
+
private ArrayMap<PlaylistEventCallback, Executor> getCallbacks() {
ArrayMap<PlaylistEventCallback, Executor> callbacks = new ArrayMap<>();
synchronized (mLock) {
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 5c18515..e099d95 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -16,7 +16,7 @@
package com.android.media;
-import static android.media.MediaSession2.COMMAND_CODE_CUSTOM;
+import static android.media.SessionCommand2.COMMAND_CODE_CUSTOM;
import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
import static android.media.SessionToken2.TYPE_SESSION;
import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
@@ -39,20 +39,18 @@
import android.media.MediaMetadata2;
import android.media.MediaPlayerBase;
import android.media.MediaPlayerBase.PlayerEventCallback;
+import android.media.MediaPlayerBase.PlayerState;
import android.media.MediaPlaylistAgent;
import android.media.MediaPlaylistAgent.PlaylistEventCallback;
import android.media.MediaSession2;
import android.media.MediaSession2.Builder;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.PlaylistParams;
-import android.media.MediaSession2.PlaylistParams.RepeatMode;
-import android.media.MediaSession2.PlaylistParams.ShuffleMode;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
-import android.media.PlaybackState2;
import android.media.SessionToken2;
import android.media.VolumeProvider2;
import android.media.session.MediaSessionManager;
@@ -64,12 +62,16 @@
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.concurrent.Executor;
public class MediaSession2Impl implements MediaSession2Provider {
@@ -86,7 +88,6 @@
private final MediaSession2Stub mSessionStub;
private final SessionToken2 mSessionToken;
private final AudioManager mAudioManager;
- private final ArrayMap<PlayerEventCallback, Executor> mCallbacks = new ArrayMap<>();
private final PendingIntent mSessionActivity;
private final PlayerEventCallback mPlayerEventCallback;
private final PlaylistEventCallback mPlaylistEventCallback;
@@ -112,9 +113,13 @@
@GuardedBy("mLock")
private MediaPlaylistAgent mPlaylistAgent;
@GuardedBy("mLock")
+ private SessionPlaylistAgent mSessionPlaylistAgent;
+ @GuardedBy("mLock")
private VolumeProvider2 mVolumeProvider;
@GuardedBy("mLock")
private PlaybackInfo mPlaybackInfo;
+ @GuardedBy("mLock")
+ private OnDataSourceMissingHelper mDsmHelper;
/**
* Can be only called by the {@link Builder#build()}.
@@ -153,13 +158,13 @@
throw new IllegalArgumentException("Ambiguous session type. Multiple"
+ " session services define the same id=" + id);
} else if (libraryService != null) {
- mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_LIBRARY_SERVICE,
+ mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_LIBRARY_SERVICE,
mContext.getPackageName(), libraryService, id, mSessionStub).getInstance();
} else if (sessionService != null) {
- mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_SESSION_SERVICE,
+ mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_SESSION_SERVICE,
mContext.getPackageName(), sessionService, id, mSessionStub).getInstance();
} else {
- mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_SESSION,
+ mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_SESSION,
mContext.getPackageName(), null, id, mSessionStub).getInstance();
}
@@ -208,7 +213,7 @@
}
@Override
- public void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
+ public void updatePlayer_impl(@NonNull MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
VolumeProvider2 volumeProvider) throws IllegalArgumentException {
ensureCallingThread();
if (player == null) {
@@ -226,9 +231,12 @@
oldPlayer = mPlayer;
oldAgent = mPlaylistAgent;
mPlayer = player;
- // TODO(jaewan): Replace this with the proper default agent (b/74090741)
if (agent == null) {
- agent = new MediaPlaylistAgent(mContext) {};
+ mSessionPlaylistAgent = new SessionPlaylistAgent(this, mPlayer);
+ if (mDsmHelper != null) {
+ mSessionPlaylistAgent.setOnDataSourceMissingHelper(mDsmHelper);
+ }
+ agent = mSessionPlaylistAgent;
}
mPlaylistAgent = agent;
mVolumeProvider = volumeProvider;
@@ -248,11 +256,12 @@
oldAgent.unregisterPlaylistEventCallback(mPlaylistEventCallback);
}
}
- // TODO(jaewan): Notify controllers about the change in the media player base (b/74370608)
- // Note that notification will be done indirectly by telling player state,
- // position, buffered position, etc.
- mSessionStub.notifyPlaybackInfoChanged(info);
- notifyPlaybackStateChangedNotLocked(mInstance.getPlaybackState());
+
+ if (oldPlayer != null) {
+ mSessionStub.notifyPlaybackInfoChanged(info);
+ notifyPlayerUpdatedNotLocked(oldPlayer);
+ }
+ // TODO(jaewan): Repeat the same thing for the playlist agent.
}
private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
@@ -271,7 +280,6 @@
}
}
info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
- mContext,
PlaybackInfo.PLAYBACK_TYPE_LOCAL,
attrs,
mAudioManager.isVolumeFixed()
@@ -281,7 +289,6 @@
mAudioManager.getStreamVolume(stream));
} else {
info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
- mContext,
PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
attrs,
volumeProvider.getControlType(),
@@ -312,6 +319,7 @@
mPlayer = null;
agent = mPlaylistAgent;
mPlaylistAgent = null;
+ mSessionPlaylistAgent = null;
}
if (player != null) {
player.unregisterPlayerEventCallback(mPlayerEventCallback);
@@ -385,36 +393,41 @@
}
@Override
- public void skipToPreviousItem_impl() {
- ensureCallingThread();
- // TODO(jaewan): Implement this (b/74175632)
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO implement
- //player.skipToPrevious();
+ public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.skipToPlaylistItem(item);
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
+ }
+
+ @Override
+ public void skipToPreviousItem_impl() {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.skipToPreviousItem();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void skipToNextItem_impl() {
- ensureCallingThread();
- // TODO(jaewan): Implement this (b/74175632)
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- player.skipToNext();
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.skipToNextItem();
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
}
@Override
- public void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout) {
+ public void setCustomLayout_impl(@NonNull ControllerInfo controller,
+ @NonNull List<CommandButton> layout) {
ensureCallingThread();
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
@@ -425,47 +438,13 @@
mSessionStub.notifyCustomLayoutNotLocked(controller, layout);
}
- @Override
- public void setPlaylistParams_impl(PlaylistParams params) {
- if (params == null) {
- throw new IllegalArgumentException("params shouldn't be null");
- }
- ensureCallingThread();
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO implement
- //player.setPlaylistParams(params);
- mSessionStub.notifyPlaylistParamsChanged(params);
- }
- */
- }
-
- @Override
- public PlaylistParams getPlaylistParams_impl() {
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO(jaewan): Is it safe to be called on any thread?
- // Otherwise MediaSession2 should cache parameter of setPlaylistParams.
- // TODO implement
- //return player.getPlaylistParams();
- return null;
- } else if (DEBUG) {
- Log.d(TAG, "API calls after the close()", new IllegalStateException());
- }
- */
- return null;
- }
-
//////////////////////////////////////////////////////////////////////////////////////
// TODO(jaewan): Implement follows
//////////////////////////////////////////////////////////////////////////////////////
@Override
- public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
+ public void setAllowedCommands_impl(@NonNull ControllerInfo controller,
+ @NonNull SessionCommandGroup2 commands) {
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
@@ -476,8 +455,8 @@
}
@Override
- public void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
- ResultReceiver receiver) {
+ public void sendCustomCommand_impl(@NonNull ControllerInfo controller,
+ @NonNull SessionCommand2 command, Bundle args, ResultReceiver receiver) {
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
@@ -488,7 +467,7 @@
}
@Override
- public void sendCustomCommand_impl(Command command, Bundle args) {
+ public void sendCustomCommand_impl(@NonNull SessionCommand2 command, Bundle args) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -496,77 +475,93 @@
}
@Override
- public void setPlaylist_impl(List<MediaItem2> playlist) {
- if (playlist == null) {
- throw new IllegalArgumentException("playlist shouldn't be null");
+ public void setPlaylist_impl(@NonNull List<MediaItem2> list, MediaMetadata2 metadata) {
+ if (list == null) {
+ throw new IllegalArgumentException("list shouldn't be null");
}
ensureCallingThread();
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO implement and use SessionPlaylistAgent
- //player.setPlaylist(playlist);
- mSessionStub.notifyPlaylistChanged(playlist);
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.setPlaylist(list, metadata);
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
}
@Override
- public void addPlaylistItem_impl(int index, MediaItem2 item) {
+ public void updatePlaylistMetadata_impl(MediaMetadata2 metadata) {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.updatePlaylistMetadata(metadata);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ }
+
+ @Override
+ public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) {
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
- // TODO(jaewan): Implement
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.addPlaylistItem(index, item);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
- public void removePlaylistItem_impl(MediaItem2 item) {
+ public void removePlaylistItem_impl(@NonNull MediaItem2 item) {
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
- // TODO(jaewan): Implement
- }
-
- @Override
- public void editPlaylistItem_impl(MediaItem2 item) {
- if (item == null) {
- throw new IllegalArgumentException("item shouldn't be null");
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.removePlaylistItem(item);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- // TODO(jaewan): Implement
}
@Override
- public void replacePlaylistItem_impl(int index, MediaItem2 item) {
+ public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) {
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
- // TODO(jaewan): Implement
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.replacePlaylistItem(index, item);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public List<MediaItem2> getPlaylist_impl() {
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO(jaewan): Is it safe to be called on any thread?
- // Otherwise MediaSession2 should cache parameter of setPlaylist.
- // TODO implement
- //return player.getPlaylist();
- return null;
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ return agent.getPlaylist();
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
+ return null;
+ }
+
+ @Override
+ public MediaMetadata2 getPlaylistMetadata_impl() {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ return agent.getPlaylistMetadata();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
return null;
}
@@ -577,6 +572,48 @@
}
@Override
+ public int getRepeatMode_impl() {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ return agent.getRepeatMode();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ return MediaPlaylistAgent.REPEAT_MODE_NONE;
+ }
+
+ @Override
+ public void setRepeatMode_impl(int repeatMode) {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.setRepeatMode(repeatMode);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ }
+
+ @Override
+ public int getShuffleMode_impl() {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ return agent.getShuffleMode();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ return MediaPlaylistAgent.SHUFFLE_MODE_NONE;
+ }
+
+ @Override
+ public void setShuffleMode_impl(int shuffleMode) {
+ final MediaPlaylistAgent agent = mPlaylistAgent;
+ if (agent != null) {
+ agent.setShuffleMode(shuffleMode);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ }
+
+ @Override
public void prepare_impl() {
ensureCallingThread();
final MediaPlayerBase player = mPlayer;
@@ -588,36 +625,6 @@
}
@Override
- public void fastForward_impl() {
- ensureCallingThread();
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO implement
- //player.fastForward();
- } else if (DEBUG) {
- Log.d(TAG, "API calls after the close()", new IllegalStateException());
- }
- */
- }
-
- @Override
- public void rewind_impl() {
- ensureCallingThread();
- // TODO: Uncomment or remove
- /*
- final MediaPlayerBase player = mPlayer;
- if (player != null) {
- // TODO implement
- //player.rewind();
- } else if (DEBUG) {
- Log.d(TAG, "API calls after the close()", new IllegalStateException());
- }
- */
- }
-
- @Override
public void seekTo_impl(long pos) {
ensureCallingThread();
final MediaPlayerBase player = mPlayer;
@@ -629,76 +636,64 @@
}
@Override
- public void skipToPlaylistItem_impl(MediaItem2 item) {
- ensureCallingThread();
- if (item == null) {
- throw new IllegalArgumentException("item shouldn't be null");
- }
- // TODO: Uncomment or remove
- /*
+ public @PlayerState int getPlayerState_impl() {
final MediaPlayerBase player = mPlayer;
if (player != null) {
- // TODO implement
- //player.setCurrentPlaylistItem(item);
+ return mPlayer.getPlayerState();
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
+ return MediaPlayerBase.PLAYER_STATE_ERROR;
}
@Override
- public void registerPlayerEventCallback_impl(Executor executor, PlayerEventCallback callback) {
- if (executor == null) {
- throw new IllegalArgumentException("executor shouldn't be null");
- }
- if (callback == null) {
- throw new IllegalArgumentException("callback shouldn't be null");
- }
- ensureCallingThread();
- if (mCallbacks.get(callback) != null) {
- Log.w(TAG, "callback is already added. Ignoring.");
- return;
- }
- mCallbacks.put(callback, executor);
- // TODO: Uncomment or remove
- /*
- // TODO(jaewan): Double check if we need this.
- final PlaybackState2 state = getInstance().getPlaybackState();
- executor.execute(() -> callback.onPlaybackStateChanged(state));
- */
- }
-
- @Override
- public void unregisterPlayerEventCallback_impl(PlayerEventCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback shouldn't be null");
- }
- ensureCallingThread();
- mCallbacks.remove(callback);
- }
-
- @Override
- public PlaybackState2 getPlaybackState_impl() {
- ensureCallingThread();
- // TODO: Uncomment or remove
- /*
+ public long getCurrentPosition_impl() {
final MediaPlayerBase player = mPlayer;
if (player != null) {
- // TODO(jaewan): Is it safe to be called on any thread?
- // Otherwise MediaSession2 should cache the result from listener.
- // TODO implement
- //return player.getPlaybackState();
- return null;
+ return mPlayer.getCurrentPosition();
} else if (DEBUG) {
Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- */
- return null;
+ return MediaPlayerBase.UNKNOWN_TIME;
+ }
+
+ @Override
+ public long getBufferedPosition_impl() {
+ final MediaPlayerBase player = mPlayer;
+ if (player != null) {
+ return mPlayer.getBufferedPosition();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ return MediaPlayerBase.UNKNOWN_TIME;
}
@Override
public void notifyError_impl(int errorCode, Bundle extras) {
- // TODO(jaewan): Implement
+ mSessionStub.notifyError(errorCode, extras);
+ }
+
+ @Override
+ public void setOnDataSourceMissingHelper_impl(@NonNull OnDataSourceMissingHelper helper) {
+ if (helper == null) {
+ throw new IllegalArgumentException("helper shouldn't be null");
+ }
+ synchronized (mLock) {
+ mDsmHelper = helper;
+ if (mSessionPlaylistAgent != null) {
+ mSessionPlaylistAgent.setOnDataSourceMissingHelper(helper);
+ }
+ }
+ }
+
+ @Override
+ public void clearOnDataSourceMissingHelper_impl() {
+ synchronized (mLock) {
+ mDsmHelper = null;
+ if (mSessionPlaylistAgent != null) {
+ mSessionPlaylistAgent.clearOnDataSourceMissingHelper();
+ }
+ }
}
///////////////////////////////////////////////////
@@ -725,35 +720,73 @@
}*/
}
- private void notifyPlaybackStateChangedNotLocked(final PlaybackState2 state) {
- ArrayMap<PlayerEventCallback, Executor> callbacks = new ArrayMap<>();
- synchronized (mLock) {
- callbacks.putAll(mCallbacks);
+ private void notifyPlaylistChangedOnExecutor(MediaPlaylistAgent playlistAgent,
+ List<MediaItem2> list, MediaMetadata2 metadata) {
+ if (playlistAgent != mPlaylistAgent) {
+ // Ignore calls from the old agent.
+ return;
}
- // Notify to callbacks added directly to this session
- for (int i = 0; i < callbacks.size(); i++) {
- final PlayerEventCallback callback = callbacks.keyAt(i);
- final Executor executor = callbacks.valueAt(i);
- // TODO: Uncomment or remove
- //executor.execute(() -> callback.onPlaybackStateChanged(state));
- }
- // Notify to controllers as well.
- mSessionStub.notifyPlaybackStateChangedNotLocked(state);
+ mCallback.onPlaylistChanged(mInstance, playlistAgent, list, metadata);
+ mSessionStub.notifyPlaylistChangedNotLocked(list, metadata);
}
- private void notifyErrorNotLocked(String mediaId, int what, int extra) {
- ArrayMap<PlayerEventCallback, Executor> callbacks = new ArrayMap<>();
- synchronized (mLock) {
- callbacks.putAll(mCallbacks);
+ private void notifyPlaylistMetadataChangedOnExecutor(MediaPlaylistAgent playlistAgent,
+ MediaMetadata2 metadata) {
+ if (playlistAgent != mPlaylistAgent) {
+ // Ignore calls from the old agent.
+ return;
}
- // Notify to callbacks added directly to this session
- for (int i = 0; i < callbacks.size(); i++) {
- final PlayerEventCallback callback = callbacks.keyAt(i);
- final Executor executor = callbacks.valueAt(i);
- // TODO: Uncomment or remove
- //executor.execute(() -> callback.onError(mediaId, what, extra));
+ mCallback.onPlaylistMetadataChanged(mInstance, playlistAgent, metadata);
+ mSessionStub.notifyPlaylistMetadataChangedNotLocked(metadata);
+ }
+
+ private void notifyRepeatModeChangedOnExecutor(MediaPlaylistAgent playlistAgent,
+ int repeatMode) {
+ if (playlistAgent != mPlaylistAgent) {
+ // Ignore calls from the old agent.
+ return;
}
- // TODO(jaewan): Notify to controllers as well.
+ mCallback.onRepeatModeChanged(mInstance, playlistAgent, repeatMode);
+ mSessionStub.notifyRepeatModeChangedNotLocked(repeatMode);
+ }
+
+ private void notifyShuffleModeChangedOnExecutor(MediaPlaylistAgent playlistAgent,
+ int shuffleMode) {
+ if (playlistAgent != mPlaylistAgent) {
+ // Ignore calls from the old agent.
+ return;
+ }
+ mCallback.onShuffleModeChanged(mInstance, playlistAgent, shuffleMode);
+ mSessionStub.notifyShuffleModeChangedNotLocked(shuffleMode);
+ }
+
+ private void notifyPlayerUpdatedNotLocked(MediaPlayerBase oldPlayer) {
+ final MediaPlayerBase player = mPlayer;
+ // TODO(jaewan): (Can be post-P) Find better way for player.getPlayerState() //
+ // In theory, Session.getXXX() may not be the same as Player.getXXX()
+ // and we should notify information of the session.getXXX() instead of
+ // player.getXXX()
+ // Notify to controllers as well.
+ final int state = player.getPlayerState();
+ if (state != oldPlayer.getPlayerState()) {
+ mSessionStub.notifyPlayerStateChangedNotLocked(state);
+ }
+
+ final long currentTimeMs = System.currentTimeMillis();
+ final long position = player.getCurrentPosition();
+ if (position != oldPlayer.getCurrentPosition()) {
+ mSessionStub.notifyPositionChangedNotLocked(currentTimeMs, position);
+ }
+
+ final float speed = player.getPlaybackSpeed();
+ if (speed != oldPlayer.getPlaybackSpeed()) {
+ mSessionStub.notifyPlaybackSpeedChangedNotLocked(speed);
+ }
+
+ final long bufferedPosition = player.getBufferedPosition();
+ if (bufferedPosition != oldPlayer.getBufferedPosition()) {
+ mSessionStub.notifyBufferedPositionChangedNotLocked(bufferedPosition);
+ }
}
Context getContext() {
@@ -768,6 +801,10 @@
return mPlayer;
}
+ MediaPlaylistAgent getPlaylistAgent() {
+ return mPlaylistAgent;
+ }
+
Executor getCallbackExecutor() {
return mCallbackExecutor;
}
@@ -803,26 +840,89 @@
@Override
public void onCurrentDataSourceChanged(MediaPlayerBase mpb, DataSourceDesc dsd) {
- super.onCurrentDataSourceChanged(mpb, dsd);
- // TODO(jaewan): Handle this b/74370608
+ MediaSession2Impl session = getSession();
+ if (session == null || dsd == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ MediaItem2 item = getMediaItem(session, dsd);
+ if (item == null) {
+ return;
+ }
+ session.getCallback().onCurrentMediaItemChanged(session.getInstance(), mpb, item);
+ // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
+ });
}
@Override
public void onMediaPrepared(MediaPlayerBase mpb, DataSourceDesc dsd) {
- super.onMediaPrepared(mpb, dsd);
- // TODO(jaewan): Handle this b/74370608
+ MediaSession2Impl session = getSession();
+ if (session == null || dsd == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ MediaItem2 item = getMediaItem(session, dsd);
+ if (item == null) {
+ return;
+ }
+ session.getCallback().onMediaPrepared(session.getInstance(), mpb, item);
+ // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
+ });
}
@Override
public void onPlayerStateChanged(MediaPlayerBase mpb, int state) {
- super.onPlayerStateChanged(mpb, state);
- // TODO(jaewan): Handle this b/74370608
+ MediaSession2Impl session = getSession();
+ if (session == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ session.getCallback().onPlayerStateChanged(session.getInstance(), mpb, state);
+ session.getSessionStub().notifyPlayerStateChangedNotLocked(state);
+ });
}
@Override
public void onBufferingStateChanged(MediaPlayerBase mpb, DataSourceDesc dsd, int state) {
- super.onBufferingStateChanged(mpb, dsd, state);
- // TODO(jaewan): Handle this b/74370608
+ MediaSession2Impl session = getSession();
+ if (session == null || dsd == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ MediaItem2 item = getMediaItem(session, dsd);
+ if (item == null) {
+ return;
+ }
+ session.getCallback().onBufferingStateChanged(
+ session.getInstance(), mpb, item, state);
+ // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
+ });
+ }
+
+ private MediaSession2Impl getSession() {
+ final MediaSession2Impl session = mSession.get();
+ if (session == null && DEBUG) {
+ Log.d(TAG, "Session is closed", new IllegalStateException());
+ }
+ return session;
+ }
+
+ private MediaItem2 getMediaItem(MediaSession2Impl session, DataSourceDesc dsd) {
+ MediaPlaylistAgent agent = session.getPlaylistAgent();
+ if (agent == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Session is closed", new IllegalStateException());
+ }
+ return null;
+ }
+ MediaItem2 item = agent.getMediaItem(dsd);
+ if (item == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Could not find matching item for dsd=" + dsd,
+ new NoSuchElementException());
+ }
+ }
+ return item;
}
}
@@ -836,27 +936,39 @@
@Override
public void onPlaylistChanged(MediaPlaylistAgent playlistAgent, List<MediaItem2> list,
MediaMetadata2 metadata) {
- super.onPlaylistChanged(playlistAgent, list, metadata);
- // TODO(jaewan): Handle this (b/74326040)
+ final MediaSession2Impl session = mSession.get();
+ if (session == null) {
+ return;
+ }
+ session.notifyPlaylistChangedOnExecutor(playlistAgent, list, metadata);
}
@Override
public void onPlaylistMetadataChanged(MediaPlaylistAgent playlistAgent,
MediaMetadata2 metadata) {
- super.onPlaylistMetadataChanged(playlistAgent, metadata);
- // TODO(jaewan): Handle this (b/74174649)
- }
-
- @Override
- public void onShuffleModeChanged(MediaPlaylistAgent playlistAgent, int shuffleMode) {
- super.onShuffleModeChanged(playlistAgent, shuffleMode);
- // TODO(jaewan): Handle this (b/74118768)
+ final MediaSession2Impl session = mSession.get();
+ if (session == null) {
+ return;
+ }
+ session.notifyPlaylistMetadataChangedOnExecutor(playlistAgent, metadata);
}
@Override
public void onRepeatModeChanged(MediaPlaylistAgent playlistAgent, int repeatMode) {
- super.onRepeatModeChanged(playlistAgent, repeatMode);
- // TODO(jaewan): Handle this (b/74118768)
+ final MediaSession2Impl session = mSession.get();
+ if (session == null) {
+ return;
+ }
+ session.notifyRepeatModeChangedOnExecutor(playlistAgent, repeatMode);
+ }
+
+ @Override
+ public void onShuffleModeChanged(MediaPlaylistAgent playlistAgent, int shuffleMode) {
+ final MediaSession2Impl session = mSession.get();
+ if (session == null) {
+ return;
+ }
+ session.notifyShuffleModeChangedOnExecutor(playlistAgent, shuffleMode);
}
}
@@ -868,20 +980,21 @@
private static final String KEY_COMMAND_EXTRAS
= "android.media.media_session2.command.extras";
- private final Command mInstance;
+ private final SessionCommand2 mInstance;
private final int mCommandCode;
// Nonnull if it's custom command
private final String mCustomCommand;
private final Bundle mExtras;
- public CommandImpl(Command instance, int commandCode) {
+ public CommandImpl(SessionCommand2 instance, int commandCode) {
mInstance = instance;
mCommandCode = commandCode;
mCustomCommand = null;
mExtras = null;
}
- public CommandImpl(Command instance, @NonNull String action, @Nullable Bundle extras) {
+ public CommandImpl(SessionCommand2 instance, @NonNull String action,
+ @Nullable Bundle extras) {
if (action == null) {
throw new IllegalArgumentException("action shouldn't be null");
}
@@ -891,14 +1004,17 @@
mExtras = extras;
}
+ @Override
public int getCommandCode_impl() {
return mCommandCode;
}
+ @Override
public @Nullable String getCustomCommand_impl() {
return mCustomCommand;
}
+ @Override
public @Nullable Bundle getExtras_impl() {
return mExtras;
}
@@ -906,6 +1022,7 @@
/**
* @return a new Bundle instance from the Command
*/
+ @Override
public Bundle toBundle_impl() {
Bundle bundle = new Bundle();
bundle.putInt(KEY_COMMAND_CODE, mCommandCode);
@@ -917,19 +1034,19 @@
/**
* @return a new Command instance from the Bundle
*/
- public static Command fromBundle_impl(Context context, Bundle command) {
+ public static SessionCommand2 fromBundle_impl(@NonNull Bundle command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
int code = command.getInt(KEY_COMMAND_CODE);
if (code != COMMAND_CODE_CUSTOM) {
- return new Command(context, code);
+ return new SessionCommand2(code);
} else {
String customCommand = command.getString(KEY_COMMAND_CUSTOM_COMMAND);
if (customCommand == null) {
return null;
}
- return new Command(context, customCommand, command.getBundle(KEY_COMMAND_EXTRAS));
+ return new SessionCommand2(customCommand, command.getBundle(KEY_COMMAND_EXTRAS));
}
}
@@ -939,8 +1056,7 @@
return false;
}
CommandImpl other = (CommandImpl) obj;
- // TODO(jaewan): Should we also compare contents in bundle?
- // It may not be possible if the bundle contains private class.
+ // TODO(jaewan): Compare Commands with the generated UUID, as we're doing for the MI2.
return mCommandCode == other.mCommandCode
&& TextUtils.equals(mCustomCommand, other.mCustomCommand);
}
@@ -954,25 +1070,37 @@
}
/**
- * Represent set of {@link Command}.
+ * Represent set of {@link SessionCommand2}.
*/
public static class CommandGroupImpl implements CommandGroupProvider {
private static final String KEY_COMMANDS =
"android.media.mediasession2.commandgroup.commands";
- private List<Command> mCommands = new ArrayList<>();
- private final Context mContext;
- private final CommandGroup mInstance;
- public CommandGroupImpl(Context context, CommandGroup instance, Object other) {
- mContext = context;
+ // Prefix for all command codes
+ private static final String PREFIX_COMMAND_CODE = "COMMAND_CODE_";
+
+ // Prefix for command codes that will be sent directly to the MediaPlayerBase
+ private static final String PREFIX_COMMAND_CODE_PLAYBACK = "COMMAND_CODE_PLAYBACK_";
+
+ // Prefix for command codes that will be sent directly to the MediaPlaylistAgent
+ private static final String PREFIX_COMMAND_CODE_PLAYLIST = "COMMAND_CODE_PLAYLIST_";
+
+ private Set<SessionCommand2> mCommands = new HashSet<>();
+ private final SessionCommandGroup2 mInstance;
+
+ public CommandGroupImpl(SessionCommandGroup2 instance, Object other) {
mInstance = instance;
if (other != null && other instanceof CommandGroupImpl) {
mCommands.addAll(((CommandGroupImpl) other).mCommands);
}
}
+ public CommandGroupImpl() {
+ mInstance = new SessionCommandGroup2(this);
+ }
+
@Override
- public void addCommand_impl(Command command) {
+ public void addCommand_impl(@NonNull SessionCommand2 command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -981,13 +1109,35 @@
@Override
public void addAllPredefinedCommands_impl() {
- for (int i = 1; i <= MediaSession2.COMMAND_CODE_MAX; i++) {
- mCommands.add(new Command(mContext, i));
+ addCommandsWithPrefix(PREFIX_COMMAND_CODE);
+ }
+
+ void addAllPlaybackCommands() {
+ addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYBACK);
+ }
+
+ void addAllPlaylistCommands() {
+ addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYLIST);
+ }
+
+ private void addCommandsWithPrefix(String prefix) {
+ // TODO(jaewan): (Can be post-P): Don't use reflection for this purpose.
+ final Field[] fields = MediaSession2.class.getFields();
+ if (fields != null) {
+ for (int i = 0; i < fields.length; i++) {
+ if (fields[i].getName().startsWith(prefix)) {
+ try {
+ mCommands.add(new SessionCommand2(fields[i].getInt(null)));
+ } catch (IllegalAccessException e) {
+ Log.w(TAG, "Unexpected " + fields[i] + " in MediaSession2");
+ }
+ }
+ }
}
}
@Override
- public void removeCommand_impl(Command command) {
+ public void removeCommand_impl(@NonNull SessionCommand2 command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -995,7 +1145,7 @@
}
@Override
- public boolean hasCommand_impl(Command command) {
+ public boolean hasCommand_impl(@NonNull SessionCommand2 command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -1007,8 +1157,8 @@
if (code == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
}
- for (int i = 0; i < mCommands.size(); i++) {
- if (mCommands.get(i).getCommandCode() == code) {
+ for (SessionCommand2 command : mCommands) {
+ if (command.getCommandCode() == code) {
return true;
}
}
@@ -1016,8 +1166,12 @@
}
@Override
- public List<Command> getCommands_impl() {
- return mCommands;
+ public Set<SessionCommand2> getCommands_impl() {
+ return getCommands();
+ }
+
+ public Set<SessionCommand2> getCommands() {
+ return Collections.unmodifiableSet(mCommands);
}
/**
@@ -1027,8 +1181,8 @@
@Override
public Bundle toBundle_impl() {
ArrayList<Bundle> list = new ArrayList<>();
- for (int i = 0; i < mCommands.size(); i++) {
- list.add(mCommands.get(i).toBundle());
+ for (SessionCommand2 command : mCommands) {
+ list.add(command.toBundle());
}
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(KEY_COMMANDS, list);
@@ -1039,7 +1193,7 @@
* @return new instance of CommandGroup from the bundle
* @hide
*/
- public static @Nullable CommandGroup fromBundle_impl(Context context, Bundle commands) {
+ public static @Nullable SessionCommandGroup2 fromBundle_impl(Bundle commands) {
if (commands == null) {
return null;
}
@@ -1047,14 +1201,14 @@
if (list == null) {
return null;
}
- CommandGroup commandGroup = new CommandGroup(context);
+ SessionCommandGroup2 commandGroup = new SessionCommandGroup2();
for (int i = 0; i < list.size(); i++) {
Parcelable parcelable = list.get(i);
if (!(parcelable instanceof Bundle)) {
continue;
}
Bundle commandBundle = (Bundle) parcelable;
- Command command = Command.fromBundle(context, commandBundle);
+ SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
if (command != null) {
commandGroup.addCommand(command);
}
@@ -1068,10 +1222,10 @@
private final int mUid;
private final String mPackageName;
private final boolean mIsTrusted;
- private final IMediaSession2Callback mControllerBinder;
+ private final IMediaController2 mControllerBinder;
public ControllerInfoImpl(Context context, ControllerInfo instance, int uid,
- int pid, String packageName, IMediaSession2Callback callback) {
+ int pid, @NonNull String packageName, @NonNull IMediaController2 callback) {
if (TextUtils.isEmpty(packageName)) {
throw new IllegalArgumentException("packageName shouldn't be empty");
}
@@ -1088,7 +1242,7 @@
// Ask server whether the controller is trusted.
// App cannot know this because apps cannot query enabled notification listener for
// another package, but system server can do.
- mIsTrusted = manager.isTrusted(uid, packageName);
+ mIsTrusted = manager.isTrusted(packageName, pid, uid);
}
@Override
@@ -1139,93 +1293,23 @@
return mControllerBinder.asBinder().equals(other.mControllerBinder.asBinder());
}
- public ControllerInfo getInstance() {
+ ControllerInfo getInstance() {
return mInstance;
}
- public IBinder getId() {
+ IBinder getId() {
return mControllerBinder.asBinder();
}
- public IMediaSession2Callback getControllerBinder() {
+ IMediaController2 getControllerBinder() {
return mControllerBinder;
}
- public static ControllerInfoImpl from(ControllerInfo controller) {
+ static ControllerInfoImpl from(ControllerInfo controller) {
return (ControllerInfoImpl) controller.getProvider();
}
}
- public static class PlaylistParamsImpl implements PlaylistParamsProvider {
- /**
- * Keys used for converting a PlaylistParams object to a bundle object and vice versa.
- */
- private static final String KEY_REPEAT_MODE =
- "android.media.session2.playlistparams2.repeat_mode";
- private static final String KEY_SHUFFLE_MODE =
- "android.media.session2.playlistparams2.shuffle_mode";
- private static final String KEY_MEDIA_METADATA2_BUNDLE =
- "android.media.session2.playlistparams2.metadata2_bundle";
-
- private Context mContext;
- private PlaylistParams mInstance;
- private @RepeatMode int mRepeatMode;
- private @ShuffleMode int mShuffleMode;
- private MediaMetadata2 mPlaylistMetadata;
-
- public PlaylistParamsImpl(Context context, PlaylistParams instance,
- @RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
- MediaMetadata2 playlistMetadata) {
- // TODO(jaewan): Sanity check
- mContext = context;
- mInstance = instance;
- mRepeatMode = repeatMode;
- mShuffleMode = shuffleMode;
- mPlaylistMetadata = playlistMetadata;
- }
-
- public @RepeatMode int getRepeatMode_impl() {
- return mRepeatMode;
- }
-
- public @ShuffleMode int getShuffleMode_impl() {
- return mShuffleMode;
- }
-
- public MediaMetadata2 getPlaylistMetadata_impl() {
- return mPlaylistMetadata;
- }
-
- @Override
- public Bundle toBundle_impl() {
- Bundle bundle = new Bundle();
- bundle.putInt(KEY_REPEAT_MODE, mRepeatMode);
- bundle.putInt(KEY_SHUFFLE_MODE, mShuffleMode);
- if (mPlaylistMetadata != null) {
- bundle.putBundle(KEY_MEDIA_METADATA2_BUNDLE, mPlaylistMetadata.toBundle());
- }
- return bundle;
- }
-
- public static PlaylistParams fromBundle(Context context, Bundle bundle) {
- if (bundle == null) {
- return null;
- }
- if (!bundle.containsKey(KEY_REPEAT_MODE) || !bundle.containsKey(KEY_SHUFFLE_MODE)) {
- return null;
- }
-
- Bundle metadataBundle = bundle.getBundle(KEY_MEDIA_METADATA2_BUNDLE);
- MediaMetadata2 metadata = metadataBundle == null
- ? null : MediaMetadata2.fromBundle(context, metadataBundle);
-
- return new PlaylistParams(context,
- bundle.getInt(KEY_REPEAT_MODE),
- bundle.getInt(KEY_SHUFFLE_MODE),
- metadata);
- }
- }
-
public static class CommandButtonImpl implements CommandButtonProvider {
private static final String KEY_COMMAND
= "android.media.media_session2.command_button.command";
@@ -1239,13 +1323,13 @@
= "android.media.media_session2.command_button.enabled";
private final CommandButton mInstance;
- private Command mCommand;
+ private SessionCommand2 mCommand;
private int mIconResId;
private String mDisplayName;
private Bundle mExtras;
private boolean mEnabled;
- public CommandButtonImpl(Context context, @Nullable Command command, int iconResId,
+ public CommandButtonImpl(@Nullable SessionCommand2 command, int iconResId,
@Nullable String displayName, Bundle extras, boolean enabled) {
mCommand = command;
mIconResId = iconResId;
@@ -1256,7 +1340,8 @@
}
@Override
- public @Nullable Command getCommand_impl() {
+ public @Nullable
+ SessionCommand2 getCommand_impl() {
return mCommand;
}
@@ -1280,7 +1365,7 @@
return mEnabled;
}
- public @NonNull Bundle toBundle() {
+ @NonNull Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putBundle(KEY_COMMAND, mCommand.toBundle());
bundle.putInt(KEY_ICON_RES_ID, mIconResId);
@@ -1290,12 +1375,12 @@
return bundle;
}
- public static @Nullable CommandButton fromBundle(Context context, Bundle bundle) {
+ static @Nullable CommandButton fromBundle(Bundle bundle) {
if (bundle == null) {
return null;
}
- CommandButton.Builder builder = new CommandButton.Builder(context);
- builder.setCommand(Command.fromBundle(context, bundle.getBundle(KEY_COMMAND)));
+ CommandButton.Builder builder = new CommandButton.Builder();
+ builder.setCommand(SessionCommand2.fromBundle(bundle.getBundle(KEY_COMMAND)));
builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0));
builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME));
builder.setExtras(bundle.getBundle(KEY_EXTRAS));
@@ -1312,22 +1397,20 @@
* Builder for {@link CommandButton}.
*/
public static class BuilderImpl implements CommandButtonProvider.BuilderProvider {
- private final Context mContext;
private final CommandButton.Builder mInstance;
- private Command mCommand;
+ private SessionCommand2 mCommand;
private int mIconResId;
private String mDisplayName;
private Bundle mExtras;
private boolean mEnabled;
- public BuilderImpl(Context context, CommandButton.Builder instance) {
- mContext = context;
+ public BuilderImpl(CommandButton.Builder instance) {
mInstance = instance;
mEnabled = true;
}
@Override
- public CommandButton.Builder setCommand_impl(Command command) {
+ public CommandButton.Builder setCommand_impl(SessionCommand2 command) {
mCommand = command;
return mInstance;
}
@@ -1367,8 +1450,8 @@
throw new IllegalStateException("Custom commands needs icon and"
+ " and name to display");
}
- return new CommandButtonImpl(
- mContext, mCommand, mIconResId, mDisplayName, mExtras, mEnabled).mInstance;
+ return new CommandButtonImpl(mCommand, mIconResId, mDisplayName, mExtras, mEnabled)
+ .mInstance;
}
}
}
@@ -1392,7 +1475,7 @@
* {@link MediaSession2} or {@link MediaController2}.
*/
// TODO(jaewan): Also need executor
- public BuilderBaseImpl(Context context) {
+ public BuilderBaseImpl(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("context shouldn't be null");
}
@@ -1402,7 +1485,7 @@
}
@Override
- public void setPlayer_impl(MediaPlayerBase player) {
+ public void setPlayer_impl(@NonNull MediaPlayerBase player) {
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
}
@@ -1410,7 +1493,7 @@
}
@Override
- public void setPlaylistAgent_impl(MediaPlaylistAgent playlistAgent) {
+ public void setPlaylistAgent_impl(@NonNull MediaPlaylistAgent playlistAgent) {
if (playlistAgent == null) {
throw new IllegalArgumentException("playlistAgent shouldn't be null");
}
@@ -1428,7 +1511,7 @@
}
@Override
- public void setId_impl(String id) {
+ public void setId_impl(@NonNull String id) {
if (id == null) {
throw new IllegalArgumentException("id shouldn't be null");
}
@@ -1436,7 +1519,7 @@
}
@Override
- public void setSessionCallback_impl(Executor executor, C callback) {
+ public void setSessionCallback_impl(@NonNull Executor executor, @NonNull C callback) {
if (executor == null) {
throw new IllegalArgumentException("executor shouldn't be null");
}
@@ -1462,7 +1545,7 @@
mCallbackExecutor = mContext.getMainExecutor();
}
if (mCallback == null) {
- mCallback = new SessionCallback(mContext) {};
+ mCallback = new SessionCallback() {};
}
return new MediaSession2Impl(mContext, mPlayer, mId, mPlaylistAgent,
mVolumeProvider, mSessionActivity, mCallbackExecutor, mCallback).getInstance();
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index a9c5224..ec657d7 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -21,28 +21,30 @@
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaLibraryService2.LibraryRoot;
-import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
+import android.media.MediaMetadata2;
+import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.PlaylistParams;
-import android.media.PlaybackState2;
import android.media.Rating2;
import android.media.VolumeProvider2;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
import com.android.media.MediaSession2Impl.CommandButtonImpl;
+import com.android.media.MediaSession2Impl.CommandGroupImpl;
import com.android.media.MediaSession2Impl.ControllerInfoImpl;
import java.lang.ref.WeakReference;
@@ -61,6 +63,9 @@
private static final String TAG = "MediaSession2Stub";
private static final boolean DEBUG = true; // TODO(jaewan): Rename.
+ private static final SparseArray<SessionCommand2> sCommandsForOnCommandRequest =
+ new SparseArray<>();
+
private final Object mLock = new Object();
private final WeakReference<MediaSession2Impl> mSession;
@@ -69,12 +74,25 @@
@GuardedBy("mLock")
private final Set<IBinder> mConnectingControllers = new HashSet<>();
@GuardedBy("mLock")
- private final ArrayMap<ControllerInfo, CommandGroup> mAllowedCommandGroupMap = new ArrayMap<>();
+ private final ArrayMap<ControllerInfo, SessionCommandGroup2> mAllowedCommandGroupMap =
+ new ArrayMap<>();
@GuardedBy("mLock")
private final ArrayMap<ControllerInfo, Set<String>> mSubscriptions = new ArrayMap<>();
public MediaSession2Stub(MediaSession2Impl session) {
mSession = new WeakReference<>(session);
+
+ synchronized (sCommandsForOnCommandRequest) {
+ if (sCommandsForOnCommandRequest.size() == 0) {
+ CommandGroupImpl group = new CommandGroupImpl();
+ group.addAllPlaybackCommands();
+ group.addAllPlaylistCommands();
+ Set<SessionCommand2> commands = group.getCommands();
+ for (SessionCommand2 command : commands) {
+ sCommandsForOnCommandRequest.append(command.getCommandCode(), command);
+ }
+ }
+ }
}
public void destroyNotLocked() {
@@ -85,7 +103,7 @@
mControllers.clear();
}
for (int i = 0; i < list.size(); i++) {
- IMediaSession2Callback controllerBinder =
+ IMediaController2 controllerBinder =
((ControllerInfoImpl) list.get(i).getProvider()).getControllerBinder();
try {
// Should be used without a lock hold to prevent potential deadlock.
@@ -113,7 +131,7 @@
}
// Get controller if the command from caller to session is able to be handled.
- private ControllerInfo getControllerIfAble(IMediaSession2Callback caller) {
+ private ControllerInfo getControllerIfAble(IMediaController2 caller) {
synchronized (mLock) {
final ControllerInfo controllerInfo = mControllers.get(caller.asBinder());
if (controllerInfo == null && DEBUG) {
@@ -124,13 +142,13 @@
}
// Get controller if the command from caller to session is able to be handled.
- private ControllerInfo getControllerIfAble(IMediaSession2Callback caller, int commandCode) {
+ private ControllerInfo getControllerIfAble(IMediaController2 caller, int commandCode) {
synchronized (mLock) {
final ControllerInfo controllerInfo = getControllerIfAble(caller);
if (controllerInfo == null) {
return null;
}
- CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
+ SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
if (allowedCommands == null) {
Log.w(TAG, "Controller with null allowed commands. Ignoring",
new IllegalStateException());
@@ -147,13 +165,13 @@
}
// Get controller if the command from caller to session is able to be handled.
- private ControllerInfo getControllerIfAble(IMediaSession2Callback caller, Command command) {
+ private ControllerInfo getControllerIfAble(IMediaController2 caller, SessionCommand2 command) {
synchronized (mLock) {
final ControllerInfo controllerInfo = getControllerIfAble(caller);
if (controllerInfo == null) {
return null;
}
- CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
+ SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
if (allowedCommands == null) {
Log.w(TAG, "Controller with null allowed commands. Ignoring",
new IllegalStateException());
@@ -170,7 +188,7 @@
}
// Return binder if the session is able to send a command to the controller.
- private IMediaSession2Callback getControllerBinderIfAble(ControllerInfo controller) {
+ private IMediaController2 getControllerBinderIfAble(ControllerInfo controller) {
if (getSession() == null) {
// getSession() already logged if session is closed.
return null;
@@ -190,10 +208,10 @@
}
// Return binder if the session is able to send a command to the controller.
- private IMediaSession2Callback getControllerBinderIfAble(ControllerInfo controller,
+ private IMediaController2 getControllerBinderIfAble(ControllerInfo controller,
int commandCode) {
synchronized (mLock) {
- CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controller);
+ SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controller);
if (allowedCommands == null) {
Log.w(TAG, "Controller with null allowed commands. Ignoring");
return null;
@@ -208,11 +226,123 @@
}
}
+ private void onCommand(@NonNull IMediaController2 caller, int commandCode,
+ @NonNull SessionRunnable runnable) {
+ final MediaSession2Impl session = getSession();
+ final ControllerInfo controller = getControllerIfAble(caller, commandCode);
+ if (session == null || controller == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ if (getControllerIfAble(caller, commandCode) == null) {
+ return;
+ }
+ SessionCommand2 command = sCommandsForOnCommandRequest.get(commandCode);
+ if (command != null) {
+ boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
+ controller, command);
+ if (!accepted) {
+ // Don't run rejected command.
+ if (DEBUG) {
+ Log.d(TAG, "Command (code=" + commandCode + ") from "
+ + controller + " was rejected by " + session);
+ }
+ return;
+ }
+ }
+ runnable.run(session, controller);
+ });
+ }
+
+ private void onBrowserCommand(@NonNull IMediaController2 caller,
+ @NonNull LibrarySessionRunnable runnable) {
+ final MediaLibrarySessionImpl session = getLibrarySession();
+ // TODO(jaewan): Consider command code
+ final ControllerInfo controller = getControllerIfAble(caller);
+ if (session == null || controller == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ // TODO(jaewan): Consider command code
+ if (getControllerIfAble(caller) == null) {
+ return;
+ }
+ runnable.run(session, controller);
+ });
+ }
+
+
+ private void notifyAll(int commandCode, @NonNull NotifyRunnable runnable) {
+ List<ControllerInfo> controllers = getControllers();
+ for (int i = 0; i < controllers.size(); i++) {
+ notifyInternal(controllers.get(i),
+ getControllerBinderIfAble(controllers.get(i), commandCode), runnable);
+ }
+ }
+
+ private void notifyAll(@NonNull NotifyRunnable runnable) {
+ List<ControllerInfo> controllers = getControllers();
+ for (int i = 0; i < controllers.size(); i++) {
+ notifyInternal(controllers.get(i),
+ getControllerBinderIfAble(controllers.get(i)), runnable);
+ }
+ }
+
+ private void notify(@NonNull ControllerInfo controller, @NonNull NotifyRunnable runnable) {
+ notifyInternal(controller, getControllerBinderIfAble(controller), runnable);
+ }
+
+ private void notify(@NonNull ControllerInfo controller, int commandCode,
+ @NonNull NotifyRunnable runnable) {
+ notifyInternal(controller, getControllerBinderIfAble(controller, commandCode), runnable);
+ }
+
+ // Do not call this API directly. Use notify() instead.
+ private void notifyInternal(@NonNull ControllerInfo controller,
+ @NonNull IMediaController2 iController, @NonNull NotifyRunnable runnable) {
+ if (controller == null || iController == null) {
+ return;
+ }
+ try {
+ runnable.run(controller, iController);
+ } catch (DeadObjectException e) {
+ if (DEBUG) {
+ Log.d(TAG, controller.toString() + " is gone", e);
+ }
+ onControllerClosed(iController);
+ } catch (RemoteException e) {
+ // Currently it's TransactionTooLargeException or DeadSystemException.
+ // We'd better to leave log for those cases because
+ // - TransactionTooLargeException means that we may need to fix our code.
+ // (e.g. add pagination or special way to deliver Bitmap)
+ // - DeadSystemException means that errors around it can be ignored.
+ Log.w(TAG, "Exception in " + controller.toString(), e);
+ }
+ }
+
+ private void onControllerClosed(IMediaController2 iController) {
+ ControllerInfo controller;
+ synchronized (mLock) {
+ controller = mControllers.remove(iController.asBinder());
+ if (DEBUG) {
+ Log.d(TAG, "releasing " + controller);
+ }
+ mSubscriptions.remove(controller);
+ }
+ final MediaSession2Impl session = getSession();
+ if (session == null || controller == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(() -> {
+ session.getCallback().onDisconnected(session.getInstance(), controller);
+ });
+ }
+
//////////////////////////////////////////////////////////////////////////////////////////////
// AIDL methods for session overrides
//////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public void connect(final IMediaSession2Callback caller, final String callingPackage)
+ public void connect(final IMediaController2 caller, final String callingPackage)
throws RuntimeException {
final MediaSession2Impl session = getSession();
if (session == null) {
@@ -231,7 +361,7 @@
// instead of pending them.
mConnectingControllers.add(ControllerInfoImpl.from(controllerInfo).getId());
}
- CommandGroup allowedCommands = session.getCallback().onConnect(
+ SessionCommandGroup2 allowedCommands = session.getCallback().onConnect(
session.getInstance(), controllerInfo);
// Don't reject connection for the request from trusted app.
// Otherwise server will fail to retrieve session's information to dispatch
@@ -245,7 +375,7 @@
}
if (allowedCommands == null) {
// For trusted apps, send non-null allowed commands to keep connection.
- allowedCommands = new CommandGroup(context);
+ allowedCommands = new SessionCommandGroup2();
}
synchronized (mLock) {
mConnectingControllers.remove(controllerImpl.getId());
@@ -256,18 +386,20 @@
// It's needed because we cannot call synchronous calls between session/controller.
// Note: We're doing this after the onConnectionChanged(), but there's no guarantee
// that events here are notified after the onConnected() because
- // IMediaSession2Callback is oneway (i.e. async call) and CallbackStub will
+ // IMediaController2 is oneway (i.e. async call) and Stub will
// use thread poll for incoming calls.
- // TODO(jaewan): Should we protect getting playback state?
- final PlaybackState2 state = session.getInstance().getPlaybackState();
- final Bundle playbackStateBundle = (state != null) ? state.toBundle() : null;
+ final int playerState = session.getInstance().getPlayerState();
+ final long positionEventTimeMs = System.currentTimeMillis();
+ final long positionMs = session.getInstance().getCurrentPosition();
+ final float playbackSpeed = session.getInstance().getPlaybackSpeed();
+ final long bufferedPositionMs = session.getInstance().getBufferedPosition();
final Bundle playbackInfoBundle = ((MediaController2Impl.PlaybackInfoImpl)
session.getPlaybackInfo().getProvider()).toBundle();
- final PlaylistParams params = session.getInstance().getPlaylistParams();
- final Bundle paramsBundle = (params != null) ? params.toBundle() : null;
+ final int repeatMode = session.getInstance().getRepeatMode();
+ final int shuffleMode = session.getInstance().getShuffleMode();
final PendingIntent sessionActivity = session.getSessionActivity();
final List<MediaItem2> playlist =
- allowedCommands.hasCommand(MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST)
+ allowedCommands.hasCommand(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST)
? session.getInstance().getPlaylist() : null;
final List<Bundle> playlistBundle;
if (playlist != null) {
@@ -292,9 +424,10 @@
return;
}
try {
- caller.onConnected(MediaSession2Stub.this,
- allowedCommands.toBundle(), playbackStateBundle, playbackInfoBundle,
- paramsBundle, playlistBundle, sessionActivity);
+ caller.onConnected(MediaSession2Stub.this, allowedCommands.toBundle(),
+ playerState, positionEventTimeMs, positionMs, playbackSpeed,
+ bufferedPositionMs, playbackInfoBundle, repeatMode, shuffleMode,
+ playlistBundle, sessionActivity);
} catch (RemoteException e) {
// Controller may be died prematurely.
// TODO(jaewan): Handle here.
@@ -317,156 +450,58 @@
}
@Override
- public void release(final IMediaSession2Callback caller) throws RemoteException {
- synchronized (mLock) {
- ControllerInfo controllerInfo = mControllers.remove(caller.asBinder());
- if (DEBUG) {
- Log.d(TAG, "releasing " + controllerInfo);
- }
- mSubscriptions.remove(controllerInfo);
- }
+ public void release(final IMediaController2 caller) throws RemoteException {
+ onControllerClosed(caller);
}
@Override
- public void setVolumeTo(final IMediaSession2Callback caller, final int value, final int flags)
+ public void setVolumeTo(final IMediaController2 caller, final int value, final int flags)
throws RuntimeException {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME) == null) {
- return;
- }
- // TODO(jaewan): Sanity check.
- Command command = new Command(
- session.getContext(), MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME);
- boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
- controller, command);
- if (!accepted) {
- // Don't run rejected command.
- if (DEBUG) {
- Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME + " from "
- + controller + " was rejected by " + session);
- }
- return;
- }
-
- VolumeProvider2 volumeProvider = session.getVolumeProvider();
- if (volumeProvider == null) {
- // TODO(jaewan): Set local stream volume
- } else {
- volumeProvider.onSetVolumeTo(value);
- }
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SET_VOLUME,
+ (session, controller) -> {
+ VolumeProvider2 volumeProvider = session.getVolumeProvider();
+ if (volumeProvider == null) {
+ // TODO(jaewan): Set local stream volume
+ } else {
+ volumeProvider.onSetVolumeTo(value);
+ }
+ });
}
@Override
- public void adjustVolume(IMediaSession2Callback caller, int direction, int flags)
+ public void adjustVolume(IMediaController2 caller, int direction, int flags)
throws RuntimeException {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME) == null) {
- return;
- }
- // TODO(jaewan): Sanity check.
- Command command = new Command(
- session.getContext(), MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME);
- boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
- controller, command);
- if (!accepted) {
- // Don't run rejected command.
- if (DEBUG) {
- Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME + " from "
- + controller + " was rejected by " + session);
- }
- return;
- }
-
- VolumeProvider2 volumeProvider = session.getVolumeProvider();
- if (volumeProvider == null) {
- // TODO(jaewan): Adjust local stream volume
- } else {
- volumeProvider.onAdjustVolume(direction);
- }
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SET_VOLUME,
+ (session, controller) -> {
+ VolumeProvider2 volumeProvider = session.getVolumeProvider();
+ if (volumeProvider == null) {
+ // TODO(jaewan): Adjust local stream volume
+ } else {
+ volumeProvider.onAdjustVolume(direction);
+ }
+ });
}
@Override
- public void sendTransportControlCommand(IMediaSession2Callback caller,
+ public void sendTransportControlCommand(IMediaController2 caller,
int commandCode, Bundle args) throws RuntimeException {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(caller, commandCode);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, commandCode) == null) {
- return;
- }
- // TODO(jaewan): Sanity check.
- Command command = new Command(session.getContext(), commandCode);
- boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
- controller, command);
- if (!accepted) {
- // Don't run rejected command.
- if (DEBUG) {
- Log.d(TAG, "Command " + commandCode + " from "
- + controller + " was rejected by " + session);
- }
- return;
- }
-
+ onCommand(caller, commandCode, (session, controller) -> {
switch (commandCode) {
- case MediaSession2.COMMAND_CODE_PLAYBACK_PLAY:
+ case SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY:
session.getInstance().play();
break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE:
+ case SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE:
session.getInstance().pause();
break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_STOP:
+ case SessionCommand2.COMMAND_CODE_PLAYBACK_STOP:
session.getInstance().stop();
break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM:
- session.getInstance().skipToPreviousItem();
- break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM:
- session.getInstance().skipToNextItem();
- break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE:
+ case SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE:
session.getInstance().prepare();
break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_FAST_FORWARD:
- session.getInstance().fastForward();
- break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_REWIND:
- session.getInstance().rewind();
- break;
- case MediaSession2.COMMAND_CODE_PLAYBACK_SEEK_TO:
+ case SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO:
session.getInstance().seekTo(args.getLong(ARGUMENT_KEY_POSITION));
break;
- case MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM:
- // TODO(jaewan): Implement
- /*
- session.getInstance().skipToPlaylistItem(
- args.getInt(ARGUMENT_KEY_ITEM_INDEX));
- */
- break;
- // TODO(jaewan): Remove (b/74116823)
- /*
- case MediaSession2.COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS:
- session.getInstance().setPlaylistParams(
- PlaylistParams.fromBundle(session.getContext(),
- args.getBundle(ARGUMENT_KEY_PLAYLIST_PARAMS)));
- break;
- */
default:
// TODO(jaewan): Resend unknown (new) commands through the custom command.
}
@@ -474,13 +509,13 @@
}
@Override
- public void sendCustomCommand(final IMediaSession2Callback caller, final Bundle commandBundle,
+ public void sendCustomCommand(final IMediaController2 caller, final Bundle commandBundle,
final Bundle args, final ResultReceiver receiver) {
final MediaSession2Impl session = getSession();
if (session == null) {
return;
}
- final Command command = Command.fromBundle(session.getContext(), commandBundle);
+ final SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
if (command == null) {
Log.w(TAG, "sendCustomCommand(): Ignoring null command from "
+ getControllerIfAble(caller));
@@ -500,67 +535,40 @@
}
@Override
- public void prepareFromUri(final IMediaSession2Callback caller, final Uri uri,
+ public void prepareFromUri(final IMediaController2 caller, final Uri uri,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_URI);
- if (session == null || controller == null) {
- return;
- }
- if (uri == null) {
- Log.w(TAG, "prepareFromUri(): Ignoring null uri from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_URI) == null) {
- return;
- }
- session.getCallback().onPrepareFromUri(session.getInstance(),
- controller, uri, extras);
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI,
+ (session, controller) -> {
+ if (uri == null) {
+ Log.w(TAG, "prepareFromUri(): Ignoring null uri from " + controller);
+ return;
+ }
+ session.getCallback().onPrepareFromUri(session.getInstance(), controller, uri,
+ extras);
+ });
}
@Override
- public void prepareFromSearch(final IMediaSession2Callback caller, final String query,
+ public void prepareFromSearch(final IMediaController2 caller, final String query,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_SEARCH);
- if (session == null || controller == null) {
- return;
- }
- if (TextUtils.isEmpty(query)) {
- Log.w(TAG, "prepareFromSearch(): Ignoring empty query from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_SEARCH) == null) {
- return;
- }
- session.getCallback().onPrepareFromSearch(session.getInstance(),
- controller, query, extras);
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH,
+ (session, controller) -> {
+ if (TextUtils.isEmpty(query)) {
+ Log.w(TAG, "prepareFromSearch(): Ignoring empty query from " + controller);
+ return;
+ }
+ session.getCallback().onPrepareFromSearch(session.getInstance(),
+ controller, query, extras);
+ });
}
@Override
- public void prepareFromMediaId(final IMediaSession2Callback caller, final String mediaId,
+ public void prepareFromMediaId(final IMediaController2 caller, final String mediaId,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_MEDIA_ID);
- if (session == null || controller == null) {
- return;
- }
- if (mediaId == null) {
- Log.w(TAG, "prepareFromMediaId(): Ignoring null mediaId from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_MEDIA_ID) == null) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
+ (session, controller) -> {
+ if (mediaId == null) {
+ Log.w(TAG, "prepareFromMediaId(): Ignoring null mediaId from " + controller);
return;
}
session.getCallback().onPrepareFromMediaId(session.getInstance(),
@@ -569,180 +577,228 @@
}
@Override
- public void playFromUri(final IMediaSession2Callback caller, final Uri uri,
+ public void playFromUri(final IMediaController2 caller, final Uri uri,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAY_FROM_URI);
- if (session == null || controller == null) {
- return;
- }
- if (uri == null) {
- Log.w(TAG, "playFromUri(): Ignoring null uri from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAY_FROM_URI) == null) {
- return;
- }
- session.getCallback().onPlayFromUri(session.getInstance(), controller, uri, extras);
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI,
+ (session, controller) -> {
+ if (uri == null) {
+ Log.w(TAG, "playFromUri(): Ignoring null uri from " + controller);
+ return;
+ }
+ session.getCallback().onPlayFromUri(session.getInstance(), controller, uri,
+ extras);
+ });
}
@Override
- public void playFromSearch(final IMediaSession2Callback caller, final String query,
+ public void playFromSearch(final IMediaController2 caller, final String query,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAY_FROM_SEARCH);
- if (session == null || controller == null) {
- return;
- }
- if (TextUtils.isEmpty(query)) {
- Log.w(TAG, "playFromSearch(): Ignoring empty query from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAY_FROM_SEARCH) == null) {
- return;
- }
- session.getCallback().onPlayFromSearch(session.getInstance(),
- controller, query, extras);
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH,
+ (session, controller) -> {
+ if (TextUtils.isEmpty(query)) {
+ Log.w(TAG, "playFromSearch(): Ignoring empty query from " + controller);
+ return;
+ }
+ session.getCallback().onPlayFromSearch(session.getInstance(),
+ controller, query, extras);
+ });
}
@Override
- public void playFromMediaId(final IMediaSession2Callback caller, final String mediaId,
+ public void playFromMediaId(final IMediaController2 caller, final String mediaId,
final Bundle extras) {
- final MediaSession2Impl session = getSession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_PLAY_FROM_MEDIA_ID);
- if (session == null || controller == null) {
- return;
- }
- if (mediaId == null) {
- Log.w(TAG, "playFromMediaId(): Ignoring null mediaId from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (session == null) {
- return;
- }
- session.getCallback().onPlayFromMediaId(session.getInstance(),
- controller, mediaId, extras);
- });
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID,
+ (session, controller) -> {
+ if (mediaId == null) {
+ Log.w(TAG, "playFromMediaId(): Ignoring null mediaId from " + controller);
+ return;
+ }
+ session.getCallback().onPlayFromMediaId(session.getInstance(), controller,
+ mediaId, extras);
+ });
}
@Override
- public void setRating(final IMediaSession2Callback caller, final String mediaId,
+ public void setRating(final IMediaController2 caller, final String mediaId,
final Bundle ratingBundle) {
- final MediaSession2Impl sessionImpl = getSession();
- final ControllerInfo controller = getControllerIfAble(caller);
- if (controller == null) {
- if (DEBUG) {
- Log.d(TAG, "Command from a controller that hasn't connected. Ignore");
- }
- return;
- }
- Rating2 rating = Rating2Impl.fromBundle(sessionImpl.getContext(), ratingBundle);
- if (rating == null) {
- Log.w(TAG, "setRating(): Ignore null rating");
- return;
- }
- sessionImpl.getCallbackExecutor().execute(() -> {
- final MediaSession2Impl session = mSession.get();
- if (session == null) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_SET_RATING,
+ (session, controller) -> {
+ if (mediaId == null) {
+ Log.w(TAG, "setRating(): Ignoring null mediaId from " + controller);
+ return;
+ }
+ if (ratingBundle == null) {
+ Log.w(TAG, "setRating(): Ignoring null ratingBundle from " + controller);
+ return;
+ }
+ Rating2 rating = Rating2.fromBundle(ratingBundle);
+ if (rating == null) {
+ if (ratingBundle == null) {
+ Log.w(TAG, "setRating(): Ignoring null rating from " + controller);
+ return;
+ }
+ return;
+ }
+ session.getCallback().onSetRating(session.getInstance(), controller, mediaId,
+ rating);
+ });
+ }
+
+ @Override
+ public void setPlaylist(final IMediaController2 caller, final List<Bundle> playlist,
+ final Bundle metadata) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST, (session, controller) -> {
+ if (playlist == null) {
+ Log.w(TAG, "setPlaylist(): Ignoring null playlist from " + controller);
return;
}
- session.getCallback().onSetRating(session.getInstance(), controller, mediaId, rating);
+ List<MediaItem2> list = new ArrayList<>();
+ for (int i = 0; i < playlist.size(); i++) {
+ // Recreates UUID in the playlist
+ MediaItem2 item = MediaItem2Impl.fromBundle(playlist.get(i), null);
+ if (item != null) {
+ list.add(item);
+ }
+ }
+ session.getInstance().setPlaylist(list, MediaMetadata2.fromBundle(metadata));
});
}
+ @Override
+ public void updatePlaylistMetadata(final IMediaController2 caller, final Bundle metadata) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA,
+ (session, controller) -> {
+ session.getInstance().updatePlaylistMetadata(MediaMetadata2.fromBundle(metadata));
+ });
+ }
+
+ @Override
+ public void addPlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM,
+ (session, controller) -> {
+ // Resets the UUID from the incoming media id, so controller may reuse a media
+ // item multiple times for addPlaylistItem.
+ session.getInstance().addPlaylistItem(index,
+ MediaItem2Impl.fromBundle(mediaItem, null));
+ });
+ }
+
+ @Override
+ public void removePlaylistItem(IMediaController2 caller, Bundle mediaItem) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM,
+ (session, controller) -> {
+ MediaItem2 item = MediaItem2.fromBundle(mediaItem);
+ // Note: MediaItem2 has hidden UUID to identify it across the processes.
+ session.getInstance().removePlaylistItem(item);
+ });
+ }
+
+ @Override
+ public void replacePlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM,
+ (session, controller) -> {
+ // Resets the UUID from the incoming media id, so controller may reuse a media
+ // item multiple times for replacePlaylistItem.
+ session.getInstance().replacePlaylistItem(index,
+ MediaItem2Impl.fromBundle(mediaItem, null));
+ });
+ }
+
+ @Override
+ public void skipToPlaylistItem(IMediaController2 caller, Bundle mediaItem) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM,
+ (session, controller) -> {
+ if (mediaItem == null) {
+ Log.w(TAG, "skipToPlaylistItem(): Ignoring null mediaItem from "
+ + controller);
+ }
+ // Note: MediaItem2 has hidden UUID to identify it across the processes.
+ session.getInstance().skipToPlaylistItem(MediaItem2.fromBundle(mediaItem));
+ });
+ }
+
+ @Override
+ public void skipToPreviousItem(IMediaController2 caller) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM,
+ (session, controller) -> {
+ session.getInstance().skipToPreviousItem();
+ });
+ }
+
+ @Override
+ public void skipToNextItem(IMediaController2 caller) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM,
+ (session, controller) -> {
+ session.getInstance().skipToNextItem();
+ });
+ }
+
+ @Override
+ public void setRepeatMode(IMediaController2 caller, int repeatMode) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE,
+ (session, controller) -> {
+ session.getInstance().setRepeatMode(repeatMode);
+ });
+ }
+
+ @Override
+ public void setShuffleMode(IMediaController2 caller, int shuffleMode) {
+ onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE,
+ (session, controller) -> {
+ session.getInstance().setShuffleMode(shuffleMode);
+ });
+ }
+
//////////////////////////////////////////////////////////////////////////////////////////////
// AIDL methods for LibrarySession overrides
//////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public void getLibraryRoot(final IMediaSession2Callback caller, final Bundle rootHints)
+ public void getLibraryRoot(final IMediaController2 caller, final Bundle rootHints)
throws RuntimeException {
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
- return;
- }
- LibraryRoot root = session.getCallback().onGetLibraryRoot(session.getInstance(),
+ onBrowserCommand(caller, (session, controller) -> {
+ final LibraryRoot root = session.getCallback().onGetLibraryRoot(session.getInstance(),
controller, rootHints);
- try {
- caller.onGetLibraryRootDone(rootHints,
+ notify(controller, (unused, iController) -> {
+ iController.onGetLibraryRootDone(rootHints,
root == null ? null : root.getRootId(),
root == null ? null : root.getExtras());
- } catch (RemoteException e) {
- // Controller may be died prematurely.
- // TODO(jaewan): Handle this.
- }
+ });
});
}
@Override
- public void getItem(final IMediaSession2Callback caller, final String mediaId)
+ public void getItem(final IMediaController2 caller, final String mediaId)
throws RuntimeException {
- if (mediaId == null) {
- if (DEBUG) {
- Log.d(TAG, "mediaId shouldn't be null");
- }
- return;
- }
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ onBrowserCommand(caller, (session, controller) -> {
+ if (mediaId == null) {
+ if (DEBUG) {
+ Log.d(TAG, "mediaId shouldn't be null");
+ }
return;
}
- MediaItem2 result = session.getCallback().onGetItem(session.getInstance(),
+ final MediaItem2 result = session.getCallback().onGetItem(session.getInstance(),
controller, mediaId);
- try {
- caller.onGetItemDone(mediaId, result == null ? null : result.toBundle());
- } catch (RemoteException e) {
- // Controller may be died prematurely.
- // TODO(jaewan): Handle this.
- }
+ notify(controller, (unused, iController) -> {
+ iController.onGetItemDone(mediaId, result == null ? null : result.toBundle());
+ });
});
}
@Override
- public void getChildren(final IMediaSession2Callback caller, final String parentId,
+ public void getChildren(final IMediaController2 caller, final String parentId,
final int page, final int pageSize, final Bundle extras) throws RuntimeException {
- if (parentId == null) {
- if (DEBUG) {
- Log.d(TAG, "parentId shouldn't be null");
+ onBrowserCommand(caller, (session, controller) -> {
+ if (parentId == null) {
+ if (DEBUG) {
+ Log.d(TAG, "parentId shouldn't be null");
+ }
+ return;
}
- return;
- }
- if (page < 1 || pageSize < 1) {
- if (DEBUG) {
- Log.d(TAG, "Neither page nor pageSize should be less than 1");
- }
- return;
- }
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ if (page < 1 || pageSize < 1) {
+ if (DEBUG) {
+ Log.d(TAG, "Neither page nor pageSize should be less than 1");
+ }
return;
}
List<MediaItem2> result = session.getCallback().onGetChildren(session.getInstance(),
@@ -752,36 +808,26 @@
+ "more than pageSize. result.size()=" + result.size() + " pageSize="
+ pageSize);
}
- List<Bundle> bundleList = null;
+ final List<Bundle> bundleList;
if (result != null) {
bundleList = new ArrayList<>();
for (MediaItem2 item : result) {
bundleList.add(item == null ? null : item.toBundle());
}
+ } else {
+ bundleList = null;
}
- try {
- caller.onGetChildrenDone(parentId, page, pageSize, bundleList, extras);
- } catch (RemoteException e) {
- // Controller may be died prematurely.
- // TODO(jaewan): Handle this.
- }
+ notify(controller, (unused, iController) -> {
+ iController.onGetChildrenDone(parentId, page, pageSize, bundleList, extras);
+ });
});
}
@Override
- public void search(IMediaSession2Callback caller, String query, Bundle extras) {
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- if (TextUtils.isEmpty(query)) {
- Log.w(TAG, "search(): Ignoring empty query from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ public void search(IMediaController2 caller, String query, Bundle extras) {
+ onBrowserCommand(caller, (session, controller) -> {
+ if (TextUtils.isEmpty(query)) {
+ Log.w(TAG, "search(): Ignoring empty query from " + controller);
return;
}
session.getCallback().onSearch(session.getInstance(), controller, query, extras);
@@ -789,25 +835,16 @@
}
@Override
- public void getSearchResult(final IMediaSession2Callback caller, final String query,
+ public void getSearchResult(final IMediaController2 caller, final String query,
final int page, final int pageSize, final Bundle extras) {
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- if (TextUtils.isEmpty(query)) {
- Log.w(TAG, "getSearchResult(): Ignoring empty query from " + controller);
- return;
- }
- if (page < 1 || pageSize < 1) {
- Log.w(TAG, "getSearchResult(): Ignoring negative page / pageSize."
- + " page=" + page + " pageSize=" + pageSize + " from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ onBrowserCommand(caller, (session, controller) -> {
+ if (TextUtils.isEmpty(query)) {
+ Log.w(TAG, "getSearchResult(): Ignoring empty query from " + controller);
+ return;
+ }
+ if (page < 1 || pageSize < 1) {
+ Log.w(TAG, "getSearchResult(): Ignoring negative page / pageSize."
+ + " page=" + page + " pageSize=" + pageSize + " from " + controller);
return;
}
List<MediaItem2> result = session.getCallback().onGetSearchResult(session.getInstance(),
@@ -817,38 +854,27 @@
+ "items more than pageSize. result.size()=" + result.size() + " pageSize="
+ pageSize);
}
- List<Bundle> bundleList = null;
+ final List<Bundle> bundleList;
if (result != null) {
bundleList = new ArrayList<>();
for (MediaItem2 item : result) {
bundleList.add(item == null ? null : item.toBundle());
}
+ } else {
+ bundleList = null;
}
-
- try {
- caller.onGetSearchResultDone(query, page, pageSize, bundleList, extras);
- } catch (RemoteException e) {
- // Controller may be died prematurely.
- // TODO(jaewan): Handle this.
- }
+ notify(controller, (unused, iController) -> {
+ iController.onGetSearchResultDone(query, page, pageSize, bundleList, extras);
+ });
});
}
@Override
- public void subscribe(final IMediaSession2Callback caller, final String parentId,
+ public void subscribe(final IMediaController2 caller, final String parentId,
final Bundle option) {
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- if (parentId == null) {
- Log.w(TAG, "subscribe(): Ignoring null parentId from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ onBrowserCommand(caller, (session, controller) -> {
+ if (parentId == null) {
+ Log.w(TAG, "subscribe(): Ignoring null parentId from " + controller);
return;
}
session.getCallback().onSubscribe(session.getInstance(),
@@ -865,19 +891,10 @@
}
@Override
- public void unsubscribe(final IMediaSession2Callback caller, final String parentId) {
- final MediaLibrarySessionImpl session = getLibrarySession();
- final ControllerInfo controller = getControllerIfAble(
- caller, MediaSession2.COMMAND_CODE_BROWSER);
- if (session == null || controller == null) {
- return;
- }
- if (parentId == null) {
- Log.w(TAG, "unsubscribe(): Ignoring null parentId from " + controller);
- return;
- }
- session.getCallbackExecutor().execute(() -> {
- if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+ public void unsubscribe(final IMediaController2 caller, final String parentId) {
+ onBrowserCommand(caller, (session, controller) -> {
+ if (parentId == null) {
+ Log.w(TAG, "unsubscribe(): Ignoring null parentId from " + controller);
return;
}
session.getCallback().onUnsubscribe(session.getInstance(), controller, parentId);
@@ -891,7 +908,7 @@
// APIs for MediaSession2Impl
//////////////////////////////////////////////////////////////////////////////////////////////
- // TODO(jaewan): Need a way to get controller with permissions
+ // TODO(jaewan): (Can be Post-P) Need a way to get controller with permissions
public List<ControllerInfo> getControllers() {
ArrayList<ControllerInfo> controllers = new ArrayList<>();
synchronized (mLock) {
@@ -903,29 +920,33 @@
}
// Should be used without a lock to prevent potential deadlock.
- public void notifyPlaybackStateChangedNotLocked(PlaybackState2 state) {
- final List<ControllerInfo> list = getControllers();
- for (int i = 0; i < list.size(); i++) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(list.get(i));
- if (controllerBinder == null) {
- return;
- }
- try {
- final Bundle bundle = state != null ? state.toBundle() : null;
- controllerBinder.onPlaybackStateChanged(bundle);
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
- }
+ public void notifyPlayerStateChangedNotLocked(int state) {
+ notifyAll((controller, iController) -> {
+ iController.onPlayerStateChanged(state);
+ });
+ }
+
+ // TODO(jaewan): Rename
+ public void notifyPositionChangedNotLocked(long eventTimeMs, long positionMs) {
+ notifyAll((controller, iController) -> {
+ iController.onPositionChanged(eventTimeMs, positionMs);
+ });
+ }
+
+ public void notifyPlaybackSpeedChangedNotLocked(float speed) {
+ notifyAll((controller, iController) -> {
+ iController.onPlaybackSpeedChanged(speed);
+ });
+ }
+
+ public void notifyBufferedPositionChangedNotLocked(long bufferedPositionMs) {
+ notifyAll((controller, iController) -> {
+ iController.onBufferedPositionChanged(bufferedPositionMs);
+ });
}
public void notifyCustomLayoutNotLocked(ControllerInfo controller, List<CommandButton> layout) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(controller);
- if (controllerBinder == null) {
- return;
- }
- try {
+ notify(controller, (unused, iController) -> {
List<Bundle> layoutBundles = new ArrayList<>();
for (int i = 0; i < layout.size(); i++) {
Bundle bundle = ((CommandButtonImpl) layout.get(i).getProvider()).toBundle();
@@ -933,88 +954,75 @@
layoutBundles.add(bundle);
}
}
- controllerBinder.onCustomLayoutChanged(layoutBundles);
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
+ iController.onCustomLayoutChanged(layoutBundles);
+ });
}
- public void notifyPlaylistChanged(List<MediaItem2> playlist) {
- final List<Bundle> bundleList = new ArrayList<>();
- for (int i = 0; i < playlist.size(); i++) {
- if (playlist.get(i) != null) {
- Bundle bundle = playlist.get(i).toBundle();
- if (bundle != null) {
- bundleList.add(bundle);
+ public void notifyPlaylistChangedNotLocked(List<MediaItem2> playlist, MediaMetadata2 metadata) {
+ final List<Bundle> bundleList;
+ if (playlist != null) {
+ bundleList = new ArrayList<>();
+ for (int i = 0; i < playlist.size(); i++) {
+ if (playlist.get(i) != null) {
+ Bundle bundle = playlist.get(i).toBundle();
+ if (bundle != null) {
+ bundleList.add(bundle);
+ }
}
}
+ } else {
+ bundleList = null;
}
- final List<ControllerInfo> list = getControllers();
- for (int i = 0; i < list.size(); i++) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(
- list.get(i), MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST);
- if (controllerBinder != null) {
- try {
- controllerBinder.onPlaylistChanged(bundleList);
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
+ final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
+ notifyAll((controller, iController) -> {
+ if (getControllerBinderIfAble(controller,
+ SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST) != null) {
+ iController.onPlaylistChanged(bundleList, metadataBundle);
+ } else if (getControllerBinderIfAble(controller,
+ SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA) != null) {
+ iController.onPlaylistMetadataChanged(metadataBundle);
}
- }
+ });
}
- public void notifyPlaylistParamsChanged(MediaSession2.PlaylistParams params) {
- final List<ControllerInfo> list = getControllers();
- for (int i = 0; i < list.size(); i++) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(list.get(i));
- if (controllerBinder == null) {
- return;
- }
- try {
- controllerBinder.onPlaylistParamsChanged(params.toBundle());
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
- }
+ public void notifyPlaylistMetadataChangedNotLocked(MediaMetadata2 metadata) {
+ final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
+ notifyAll(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA,
+ (unused, iController) -> {
+ iController.onPlaylistMetadataChanged(metadataBundle);
+ });
+ }
+
+ public void notifyRepeatModeChangedNotLocked(int repeatMode) {
+ notifyAll((unused, iController) -> {
+ iController.onRepeatModeChanged(repeatMode);
+ });
+ }
+
+ public void notifyShuffleModeChangedNotLocked(int shuffleMode) {
+ notifyAll((unused, iController) -> {
+ iController.onShuffleModeChanged(shuffleMode);
+ });
}
public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
- final List<ControllerInfo> list = getControllers();
- for (int i = 0; i < list.size(); i++) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(list.get(i));
- if (controllerBinder == null) {
- return;
- }
- try {
- controllerBinder.onPlaybackInfoChanged(((MediaController2Impl.PlaybackInfoImpl)
- playbackInfo.getProvider()).toBundle());
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
- }
+ final Bundle playbackInfoBundle =
+ ((MediaController2Impl.PlaybackInfoImpl) playbackInfo.getProvider()).toBundle();
+ notifyAll((unused, iController) -> {
+ iController.onPlaybackInfoChanged(playbackInfoBundle);
+ });
}
- public void setAllowedCommands(ControllerInfo controller, CommandGroup commands) {
+ public void setAllowedCommands(ControllerInfo controller, SessionCommandGroup2 commands) {
synchronized (mLock) {
mAllowedCommandGroupMap.put(controller, commands);
}
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(controller);
- if (controllerBinder == null) {
- return;
- }
- try {
- controllerBinder.onAllowedCommandsChanged(commands.toBundle());
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
+ notify(controller, (unused, iController) -> {
+ iController.onAllowedCommandsChanged(commands.toBundle());
+ });
}
- public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
+ public void sendCustomCommand(ControllerInfo controller, SessionCommand2 command, Bundle args,
ResultReceiver receiver) {
if (receiver != null && controller == null) {
throw new IllegalArgumentException("Controller shouldn't be null if result receiver is"
@@ -1023,32 +1031,26 @@
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
- sendCustomCommandInternal(controller, command, args, receiver);
+ notify(controller, (unused, iController) -> {
+ Bundle commandBundle = command.toBundle();
+ iController.onCustomCommand(commandBundle, args, null);
+ });
}
- public void sendCustomCommand(Command command, Bundle args) {
+ public void sendCustomCommand(SessionCommand2 command, Bundle args) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
- final List<ControllerInfo> controllers = getControllers();
- for (int i = 0; i < controllers.size(); i++) {
- sendCustomCommand(controllers.get(i), command, args, null);
- }
+ Bundle commandBundle = command.toBundle();
+ notifyAll((unused, iController) -> {
+ iController.onCustomCommand(commandBundle, args, null);
+ });
}
- private void sendCustomCommandInternal(ControllerInfo controller, Command command, Bundle args,
- ResultReceiver receiver) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(controller);
- if (controllerBinder == null) {
- return;
- }
- try {
- Bundle commandBundle = command.toBundle();
- controllerBinder.onCustomCommand(commandBundle, args, receiver);
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
+ public void notifyError(int errorCode, Bundle extras) {
+ notifyAll((unused, iController) -> {
+ iController.onError(errorCode, extras);
+ });
}
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -1057,48 +1059,55 @@
public void notifySearchResultChanged(ControllerInfo controller, String query, int itemCount,
Bundle extras) {
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(controller);
- if (controllerBinder == null) {
- return;
- }
- try {
- controllerBinder.onSearchResultChanged(query, itemCount, extras);
- } catch (RemoteException e) {
- Log.w(TAG, "Controller is gone", e);
- // TODO(jaewan): What to do when the controller is gone?
- }
+ notify(controller, (unused, iController) -> {
+ iController.onSearchResultChanged(query, itemCount, extras);
+ });
}
public void notifyChildrenChangedNotLocked(ControllerInfo controller, String parentId,
int itemCount, Bundle extras) {
- notifyChildrenChangedInternalNotLocked(controller, parentId, itemCount, extras);
+ notify(controller, (unused, iController) -> {
+ if (isSubscribed(controller, parentId)) {
+ iController.onChildrenChanged(parentId, itemCount, extras);
+ }
+ });
}
public void notifyChildrenChangedNotLocked(String parentId, int itemCount, Bundle extras) {
- final List<ControllerInfo> controllers = getControllers();
- for (int i = 0; i < controllers.size(); i++) {
- notifyChildrenChangedInternalNotLocked(controllers.get(i), parentId, itemCount,
- extras);
- }
+ notifyAll((controller, iController) -> {
+ if (isSubscribed(controller, parentId)) {
+ iController.onChildrenChanged(parentId, itemCount, extras);
+ }
+ });
}
- public void notifyChildrenChangedInternalNotLocked(final ControllerInfo controller,
- String parentId, int itemCount, Bundle extras) {
- // Ensure subscription
+ private boolean isSubscribed(ControllerInfo controller, String parentId) {
synchronized (mLock) {
Set<String> subscriptions = mSubscriptions.get(controller);
if (subscriptions == null || !subscriptions.contains(parentId)) {
- return;
+ return false;
}
}
- final IMediaSession2Callback controllerBinder = getControllerBinderIfAble(controller);
- if (controller == null) {
- return;
- }
- try {
- controllerBinder.onChildrenChanged(parentId, itemCount, extras);
- } catch (RemoteException e) {
- // TODO(jaewan): Handle controller removed?
- }
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Misc
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ @FunctionalInterface
+ private interface SessionRunnable {
+ void run(final MediaSession2Impl session, final ControllerInfo controller);
+ }
+
+ @FunctionalInterface
+ private interface LibrarySessionRunnable {
+ void run(final MediaLibrarySessionImpl session, final ControllerInfo controller);
+ }
+
+ @FunctionalInterface
+ private interface NotifyRunnable {
+ void run(final ControllerInfo controller,
+ final IMediaController2 iController) throws RemoteException;
}
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index 6bd2b2a..c33eb65 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -27,10 +27,8 @@
import android.media.MediaSession2;
import android.media.MediaSessionService2;
import android.media.MediaSessionService2.MediaNotification;
-import android.media.PlaybackState2;
import android.media.SessionToken2;
import android.media.SessionToken2.TokenType;
-import android.media.session.PlaybackState;
import android.media.update.MediaSessionService2Provider;
import android.os.IBinder;
import android.support.annotation.GuardedBy;
@@ -109,13 +107,13 @@
return null;
}
- private void updateNotification(PlaybackState2 state) {
+ private void updateNotification(int playerState) {
MediaNotification mediaNotification = mInstance.onUpdateNotification();
if (mediaNotification == null) {
return;
}
- switch((int) state.getState()) {
- case PlaybackState.STATE_PLAYING:
+ switch(playerState) {
+ case MediaPlayerBase.PLAYER_STATE_PLAYING:
if (!mIsRunningForeground) {
mIsRunningForeground = true;
mInstance.startForegroundService(mStartSelfIntent);
@@ -124,7 +122,8 @@
return;
}
break;
- case PlaybackState.STATE_STOPPED:
+ case MediaPlayerBase.PLAYER_STATE_IDLE:
+ case MediaPlayerBase.PLAYER_STATE_ERROR:
if (mIsRunningForeground) {
mIsRunningForeground = false;
mInstance.stopForeground(true);
@@ -142,23 +141,14 @@
// TODO: Implement this
return;
}
- // TODO: Uncomment or remove
- //public void onPlaybackStateChanged(PlaybackState2 state) {
- // if (state == null) {
- // Log.w(TAG, "Ignoring null playback state");
- // return;
- // }
- // MediaSession2Impl impl = (MediaSession2Impl) mSession.getProvider();
- // updateNotification(impl.getInstance().getPlaybackState());
- //}
}
public static class MediaNotificationImpl implements MediaNotificationProvider {
private int mNotificationId;
private Notification mNotification;
- public MediaNotificationImpl(Context context, MediaNotification instance,
- int notificationId, Notification notification) {
+ public MediaNotificationImpl(MediaNotification instance, int notificationId,
+ Notification notification) {
if (notification == null) {
throw new IllegalArgumentException("notification shouldn't be null");
}
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java b/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
deleted file mode 100644
index ee8d6d7..0000000
--- a/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-package com.android.media;
-
-import android.content.Context;
-import android.media.PlaybackState2;
-import android.media.update.PlaybackState2Provider;
-import android.os.Bundle;
-
-public final class PlaybackState2Impl implements PlaybackState2Provider {
- /**
- * Keys used for converting a PlaybackState2 to a bundle object and vice versa.
- */
- private static final String KEY_STATE = "android.media.playbackstate2.state";
- private static final String KEY_POSITION = "android.media.playbackstate2.position";
- private static final String KEY_BUFFERED_POSITION =
- "android.media.playbackstate2.buffered_position";
- private static final String KEY_SPEED = "android.media.playbackstate2.speed";
- private static final String KEY_UPDATE_TIME = "android.media.playbackstate2.update_time";
- private static final String KEY_ACTIVE_ITEM_ID = "android.media.playbackstate2.active_item_id";
-
- private final Context mContext;
- private final PlaybackState2 mInstance;
- private final int mState;
- private final long mPosition;
- private final long mUpdateTime;
- private final float mSpeed;
- private final long mBufferedPosition;
- private final long mActiveItemId;
-
- public PlaybackState2Impl(Context context, PlaybackState2 instance, int state, long position,
- long updateTime, float speed, long bufferedPosition, long activeItemId) {
- mContext = context;
- mInstance = instance;
- mState = state;
- mPosition = position;
- mSpeed = speed;
- mUpdateTime = updateTime;
- mBufferedPosition = bufferedPosition;
- mActiveItemId = activeItemId;
- }
-
- @Override
- public String toString_impl() {
- StringBuilder bob = new StringBuilder("PlaybackState {");
- bob.append("state=").append(mState);
- bob.append(", position=").append(mPosition);
- bob.append(", buffered position=").append(mBufferedPosition);
- bob.append(", speed=").append(mSpeed);
- bob.append(", updated=").append(mUpdateTime);
- bob.append(", active item id=").append(mActiveItemId);
- bob.append("}");
- return bob.toString();
- }
-
- @Override
- public int getState_impl() {
- return mState;
- }
-
- @Override
- public long getPosition_impl() {
- return mPosition;
- }
-
- @Override
- public long getBufferedPosition_impl() {
- return mBufferedPosition;
- }
-
- @Override
- public float getPlaybackSpeed_impl() {
- return mSpeed;
- }
-
- @Override
- public long getLastPositionUpdateTime_impl() {
- return mUpdateTime;
- }
-
- @Override
- public long getCurrentPlaylistItemIndex_impl() {
- return mActiveItemId;
- }
-
- @Override
- public Bundle toBundle_impl() {
- Bundle bundle = new Bundle();
- bundle.putInt(KEY_STATE, mState);
- bundle.putLong(KEY_POSITION, mPosition);
- bundle.putLong(KEY_UPDATE_TIME, mUpdateTime);
- bundle.putFloat(KEY_SPEED, mSpeed);
- bundle.putLong(KEY_BUFFERED_POSITION, mBufferedPosition);
- bundle.putLong(KEY_ACTIVE_ITEM_ID, mActiveItemId);
- return bundle;
- }
-
- public static PlaybackState2 fromBundle(Context context, Bundle bundle) {
- if (bundle == null) {
- return null;
- }
- if (!bundle.containsKey(KEY_STATE)
- || !bundle.containsKey(KEY_POSITION)
- || !bundle.containsKey(KEY_UPDATE_TIME)
- || !bundle.containsKey(KEY_SPEED)
- || !bundle.containsKey(KEY_BUFFERED_POSITION)
- || !bundle.containsKey(KEY_ACTIVE_ITEM_ID)) {
- return null;
- }
- return new PlaybackState2(context,
- bundle.getInt(KEY_STATE),
- bundle.getLong(KEY_POSITION),
- bundle.getLong(KEY_UPDATE_TIME),
- bundle.getFloat(KEY_SPEED),
- bundle.getLong(KEY_BUFFERED_POSITION),
- bundle.getLong(KEY_ACTIVE_ITEM_ID));
- }
-}
\ No newline at end of file
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
index 68e104a..d558129 100644
--- a/packages/MediaComponents/src/com/android/media/Rating2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
@@ -39,7 +39,7 @@
private final int mRatingStyle;
private final float mRatingValue;
- private Rating2Impl(Context context, @Style int ratingStyle, float rating) {
+ private Rating2Impl(@Style int ratingStyle, float rating) {
mRatingStyle = ratingStyle;
mRatingValue = rating;
mInstance = new Rating2(this);
@@ -66,16 +66,15 @@
return Objects.hash(mRatingStyle, mRatingValue);
}
- public Rating2 getInstance() {
+ Rating2 getInstance() {
return mInstance;
}
- public static Rating2 fromBundle(Context context, Bundle bundle) {
+ public static Rating2 fromBundle_impl(Bundle bundle) {
if (bundle == null) {
return null;
}
- return new Rating2Impl(context, bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE))
- .getInstance();
+ return new Rating2Impl(bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE)).getInstance();
}
public Bundle toBundle_impl() {
@@ -85,7 +84,7 @@
return bundle;
}
- public static Rating2 newUnratedRating(Context context, @Style int ratingStyle) {
+ public static Rating2 newUnratedRating_impl(@Style int ratingStyle) {
switch(ratingStyle) {
case RATING_HEART:
case RATING_THUMB_UP_DOWN:
@@ -93,22 +92,21 @@
case RATING_4_STARS:
case RATING_5_STARS:
case RATING_PERCENTAGE:
- return new Rating2Impl(context, ratingStyle, RATING_NOT_RATED).getInstance();
+ return new Rating2Impl(ratingStyle, RATING_NOT_RATED).getInstance();
default:
return null;
}
}
- public static Rating2 newHeartRating(Context context, boolean hasHeart) {
- return new Rating2Impl(context, RATING_HEART, hasHeart ? 1.0f : 0.0f).getInstance();
+ public static Rating2 newHeartRating_impl(boolean hasHeart) {
+ return new Rating2Impl(RATING_HEART, hasHeart ? 1.0f : 0.0f).getInstance();
}
- public static Rating2 newThumbRating(Context context, boolean thumbIsUp) {
- return new Rating2Impl(context, RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f)
- .getInstance();
+ public static Rating2 newThumbRating_impl(boolean thumbIsUp) {
+ return new Rating2Impl(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f).getInstance();
}
- public static Rating2 newStarRating(Context context, int starRatingStyle, float starRating) {
+ public static Rating2 newStarRating_impl(int starRatingStyle, float starRating) {
float maxRating = RATING_NOT_RATED;
switch(starRatingStyle) {
case RATING_3_STARS:
@@ -128,15 +126,15 @@
Log.e(TAG, "Trying to set out of range star-based rating");
return null;
}
- return new Rating2Impl(context, starRatingStyle, starRating).getInstance();
+ return new Rating2Impl(starRatingStyle, starRating).getInstance();
}
- public static Rating2 newPercentageRating(Context context, float percent) {
+ public static Rating2 newPercentageRating_impl(float percent) {
if ((percent < 0.0f) || (percent > 100.0f)) {
Log.e(TAG, "Invalid percentage-based rating value");
return null;
} else {
- return new Rating2Impl(context, RATING_PERCENTAGE, percent).getInstance();
+ return new Rating2Impl(RATING_PERCENTAGE, percent).getInstance();
}
}
diff --git a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
new file mode 100644
index 0000000..1c570aa
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlayerBase;
+import android.media.MediaPlayerBase.PlayerEventCallback;
+import android.media.MediaPlaylistAgent;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class SessionPlaylistAgent extends MediaPlaylistAgent {
+ private static final String TAG = "SessionPlaylistAgent";
+ @VisibleForTesting
+ static final int END_OF_PLAYLIST = -1;
+ @VisibleForTesting
+ static final int NO_VALID_ITEMS = -2;
+
+ private final PlayItem mEopPlayItem = new PlayItem(END_OF_PLAYLIST, null);
+
+ private final Object mLock = new Object();
+ private final MediaSession2Impl mSessionImpl;
+ private final MyPlayerEventCallback mPlayerCallback;
+
+ @GuardedBy("mLock")
+ private MediaPlayerBase mPlayer;
+ @GuardedBy("mLock")
+ private OnDataSourceMissingHelper mDsmHelper;
+ // TODO: Check if having the same item is okay (b/74090741)
+ @GuardedBy("mLock")
+ private ArrayList<MediaItem2> mPlaylist = new ArrayList<>();
+ @GuardedBy("mLock")
+ private ArrayList<MediaItem2> mShuffledList = new ArrayList<>();
+ @GuardedBy("mLock")
+ private Map<MediaItem2, DataSourceDesc> mItemDsdMap = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private MediaMetadata2 mMetadata;
+ @GuardedBy("mLock")
+ private int mRepeatMode;
+ @GuardedBy("mLock")
+ private int mShuffleMode;
+ @GuardedBy("mLock")
+ private PlayItem mCurrent;
+
+ // Called on session callback executor.
+ private class MyPlayerEventCallback extends PlayerEventCallback {
+ public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb,
+ @Nullable DataSourceDesc dsd) {
+ if (mPlayer != mpb) {
+ return;
+ }
+ synchronized (mLock) {
+ if (dsd == null && mCurrent != null) {
+ mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
+ updateCurrentIfNeededLocked();
+ }
+ }
+ }
+ }
+
+ private class PlayItem {
+ int shuffledIdx;
+ DataSourceDesc dsd;
+ MediaItem2 mediaItem;
+
+ PlayItem(int shuffledIdx) {
+ this(shuffledIdx, null);
+ }
+
+ PlayItem(int shuffledIdx, DataSourceDesc dsd) {
+ this.shuffledIdx = shuffledIdx;
+ if (shuffledIdx >= 0) {
+ this.mediaItem = mShuffledList.get(shuffledIdx);
+ if (dsd == null) {
+ synchronized (mLock) {
+ this.dsd = retrieveDataSourceDescLocked(this.mediaItem);
+ }
+ } else {
+ this.dsd = dsd;
+ }
+ }
+ }
+
+ boolean isValid() {
+ if (this == mEopPlayItem) {
+ return true;
+ }
+ if (mediaItem == null) {
+ return false;
+ }
+ if (dsd == null) {
+ return false;
+ }
+ if (shuffledIdx >= mShuffledList.size()) {
+ return false;
+ }
+ if (mediaItem != mShuffledList.get(shuffledIdx)) {
+ return false;
+ }
+ if (mediaItem.getDataSourceDesc() != null
+ && !mediaItem.getDataSourceDesc().equals(dsd)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public SessionPlaylistAgent(@NonNull MediaSession2Impl sessionImpl,
+ @NonNull MediaPlayerBase player) {
+ if (sessionImpl == null) {
+ throw new IllegalArgumentException("sessionImpl shouldn't be null");
+ }
+ if (player == null) {
+ throw new IllegalArgumentException("player shouldn't be null");
+ }
+ mSessionImpl = sessionImpl;
+ mPlayer = player;
+ mPlayerCallback = new MyPlayerEventCallback();
+ mPlayer.registerPlayerEventCallback(mSessionImpl.getCallbackExecutor(), mPlayerCallback);
+ }
+
+ public void setPlayer(@NonNull MediaPlayerBase player) {
+ if (player == null) {
+ throw new IllegalArgumentException("player shouldn't be null");
+ }
+ synchronized (mLock) {
+ if (player == mPlayer) {
+ return;
+ }
+ mPlayer.unregisterPlayerEventCallback(mPlayerCallback);
+ mPlayer = player;
+ mPlayer.registerPlayerEventCallback(
+ mSessionImpl.getCallbackExecutor(), mPlayerCallback);
+ updatePlayerDataSourceLocked();
+ }
+ }
+
+ public void setOnDataSourceMissingHelper(OnDataSourceMissingHelper helper) {
+ synchronized (mLock) {
+ mDsmHelper = helper;
+ }
+ }
+
+ public void clearOnDataSourceMissingHelper() {
+ synchronized (mLock) {
+ mDsmHelper = null;
+ }
+ }
+
+ @Override
+ public @Nullable List<MediaItem2> getPlaylist() {
+ synchronized (mLock) {
+ return Collections.unmodifiableList(mPlaylist);
+ }
+ }
+
+ @Override
+ public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
+ if (list == null) {
+ throw new IllegalArgumentException("list shouldn't be null");
+ }
+
+ synchronized (mLock) {
+ mItemDsdMap.clear();
+
+ mPlaylist.clear();
+ mPlaylist.addAll(list);
+ applyShuffleModeLocked();
+
+ mMetadata = metadata;
+ mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
+ }
+ notifyPlaylistChanged();
+ }
+
+ @Override
+ public @Nullable MediaMetadata2 getPlaylistMetadata() {
+ return mMetadata;
+ }
+
+ @Override
+ public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
+ synchronized (mLock) {
+ if (metadata == mMetadata) {
+ return;
+ }
+ mMetadata = metadata;
+ }
+ notifyPlaylistMetadataChanged();
+ }
+
+ @Override
+ public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ synchronized (mLock) {
+ index = clamp(index, mPlaylist.size());
+ int shuffledIdx = index;
+ mPlaylist.add(index, item);
+ if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_NONE) {
+ mShuffledList.add(index, item);
+ } else {
+ // Add the item in random position of mShuffledList.
+ shuffledIdx = ThreadLocalRandom.current().nextInt(mShuffledList.size() + 1);
+ mShuffledList.add(shuffledIdx, item);
+ }
+ if (!hasValidItem()) {
+ mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
+ } else {
+ updateCurrentIfNeededLocked();
+ }
+ }
+ notifyPlaylistChanged();
+ }
+
+ @Override
+ public void removePlaylistItem(@NonNull MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ synchronized (mLock) {
+ if (!mPlaylist.remove(item)) {
+ return;
+ }
+ mShuffledList.remove(item);
+ mItemDsdMap.remove(item);
+ updateCurrentIfNeededLocked();
+ }
+ notifyPlaylistChanged();
+ }
+
+ @Override
+ public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ synchronized (mLock) {
+ if (mPlaylist.size() <= 0) {
+ return;
+ }
+ index = clamp(index, mPlaylist.size() - 1);
+ int shuffledIdx = mShuffledList.indexOf(mPlaylist.get(index));
+ mItemDsdMap.remove(mShuffledList.get(shuffledIdx));
+ mShuffledList.set(shuffledIdx, item);
+ mPlaylist.set(index, item);
+ if (!hasValidItem()) {
+ mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
+ } else {
+ updateCurrentIfNeededLocked();
+ }
+ }
+ notifyPlaylistChanged();
+ }
+
+ @Override
+ public void skipToPlaylistItem(@NonNull MediaItem2 item) {
+ if (item == null) {
+ throw new IllegalArgumentException("item shouldn't be null");
+ }
+ synchronized (mLock) {
+ if (!hasValidItem() || item.equals(mCurrent.mediaItem)) {
+ return;
+ }
+ int shuffledIdx = mShuffledList.indexOf(item);
+ if (shuffledIdx < 0) {
+ return;
+ }
+ mCurrent = new PlayItem(shuffledIdx);
+ updateCurrentIfNeededLocked();
+ }
+ }
+
+ @Override
+ public void skipToPreviousItem() {
+ synchronized (mLock) {
+ if (!hasValidItem()) {
+ return;
+ }
+ PlayItem prev = getNextValidPlayItemLocked(mCurrent.shuffledIdx, -1);
+ if (prev != mEopPlayItem) {
+ mCurrent = prev;
+ }
+ updateCurrentIfNeededLocked();
+ }
+ }
+
+ @Override
+ public void skipToNextItem() {
+ synchronized (mLock) {
+ if (!hasValidItem() || mCurrent == mEopPlayItem) {
+ return;
+ }
+ PlayItem next = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
+ if (next != mEopPlayItem) {
+ mCurrent = next;
+ }
+ updateCurrentIfNeededLocked();
+ }
+ }
+
+ @Override
+ public int getRepeatMode() {
+ return mRepeatMode;
+ }
+
+ @Override
+ public void setRepeatMode(int repeatMode) {
+ if (repeatMode < MediaPlaylistAgent.REPEAT_MODE_NONE
+ || repeatMode > MediaPlaylistAgent.REPEAT_MODE_GROUP) {
+ return;
+ }
+ synchronized (mLock) {
+ if (mRepeatMode == repeatMode) {
+ return;
+ }
+ mRepeatMode = repeatMode;
+ switch (repeatMode) {
+ case MediaPlaylistAgent.REPEAT_MODE_ONE:
+ if (mCurrent != null && mCurrent != mEopPlayItem) {
+ mPlayer.loopCurrent(true);
+ }
+ break;
+ case MediaPlaylistAgent.REPEAT_MODE_ALL:
+ case MediaPlaylistAgent.REPEAT_MODE_GROUP:
+ if (mCurrent == mEopPlayItem) {
+ mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
+ }
+ // pass through
+ case MediaPlaylistAgent.REPEAT_MODE_NONE:
+ mPlayer.loopCurrent(false);
+ break;
+ }
+ }
+ notifyRepeatModeChanged();
+ }
+
+ @Override
+ public int getShuffleMode() {
+ return mShuffleMode;
+ }
+
+ @Override
+ public void setShuffleMode(int shuffleMode) {
+ if (shuffleMode < MediaPlaylistAgent.SHUFFLE_MODE_NONE
+ || shuffleMode > MediaPlaylistAgent.SHUFFLE_MODE_GROUP) {
+ return;
+ }
+ synchronized (mLock) {
+ if (mShuffleMode == shuffleMode) {
+ return;
+ }
+ mShuffleMode = shuffleMode;
+ applyShuffleModeLocked();
+ updateCurrentIfNeededLocked();
+ }
+ notifyShuffleModeChanged();
+ }
+
+ @VisibleForTesting
+ int getCurShuffledIndex() {
+ return hasValidItem() ? mCurrent.shuffledIdx : NO_VALID_ITEMS;
+ }
+
+ private boolean hasValidItem() {
+ return mCurrent != null;
+ }
+
+ private DataSourceDesc retrieveDataSourceDescLocked(MediaItem2 item) {
+ DataSourceDesc dsd = item.getDataSourceDesc();
+ if (dsd != null) {
+ mItemDsdMap.put(item, dsd);
+ return dsd;
+ }
+ dsd = mItemDsdMap.get(item);
+ if (dsd != null) {
+ return dsd;
+ }
+ OnDataSourceMissingHelper helper = mDsmHelper;
+ if (helper != null) {
+ // TODO: Do not call onDataSourceMissing with the lock (b/74090741).
+ dsd = helper.onDataSourceMissing(mSessionImpl.getInstance(), item);
+ if (dsd != null) {
+ mItemDsdMap.put(item, dsd);
+ }
+ }
+ return dsd;
+ }
+
+ // TODO: consider to call updateCurrentIfNeededLocked inside (b/74090741)
+ private PlayItem getNextValidPlayItemLocked(int curShuffledIdx, int direction) {
+ int size = mPlaylist.size();
+ if (curShuffledIdx == END_OF_PLAYLIST) {
+ curShuffledIdx = (direction > 0) ? -1 : size;
+ }
+ for (int i = 0; i < size; i++) {
+ curShuffledIdx += direction;
+ if (curShuffledIdx < 0 || curShuffledIdx >= mPlaylist.size()) {
+ if (mRepeatMode == REPEAT_MODE_NONE) {
+ return (i == size - 1) ? null : mEopPlayItem;
+ } else {
+ curShuffledIdx = curShuffledIdx < 0 ? mPlaylist.size() - 1 : 0;
+ }
+ }
+ DataSourceDesc dsd = retrieveDataSourceDescLocked(mShuffledList.get(curShuffledIdx));
+ if (dsd != null) {
+ return new PlayItem(curShuffledIdx, dsd);
+ }
+ }
+ return null;
+ }
+
+ private void updateCurrentIfNeededLocked() {
+ if (!hasValidItem() || mCurrent.isValid()) {
+ return;
+ }
+ int shuffledIdx = mShuffledList.indexOf(mCurrent.mediaItem);
+ if (shuffledIdx >= 0) {
+ // Added an item.
+ mCurrent.shuffledIdx = shuffledIdx;
+ return;
+ }
+
+ if (mCurrent.shuffledIdx >= mShuffledList.size()) {
+ mCurrent = getNextValidPlayItemLocked(mShuffledList.size() - 1, 1);
+ } else {
+ mCurrent.mediaItem = mShuffledList.get(mCurrent.shuffledIdx);
+ if (retrieveDataSourceDescLocked(mCurrent.mediaItem) == null) {
+ mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
+ }
+ }
+ updatePlayerDataSourceLocked();
+ return;
+ }
+
+ private void updatePlayerDataSourceLocked() {
+ if (mCurrent == null || mCurrent == mEopPlayItem) {
+ return;
+ }
+ if (mPlayer.getCurrentDataSource() != mCurrent.dsd) {
+ mPlayer.setDataSource(mCurrent.dsd);
+ mPlayer.loopCurrent(mRepeatMode == MediaPlaylistAgent.REPEAT_MODE_ONE);
+ }
+ // TODO: Call setNextDataSource (b/74090741)
+ }
+
+ private void applyShuffleModeLocked() {
+ mShuffledList.clear();
+ mShuffledList.addAll(mPlaylist);
+ if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_ALL
+ || mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_GROUP) {
+ Collections.shuffle(mShuffledList);
+ }
+ }
+
+ // Clamps value to [0, size]
+ private static int clamp(int value, int size) {
+ if (value < 0) {
+ return 0;
+ }
+ return (value > size) ? size : value;
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index 723622e..a5cf8c4 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -98,8 +98,8 @@
mSessionBinder = null;
}
- public SessionToken2Impl(Context context, int uid, int type,
- String packageName, String serviceName, String id, IMediaSession2 sessionBinder) {
+ SessionToken2Impl(int uid, int type, String packageName, String serviceName, String id,
+ IMediaSession2 sessionBinder) {
// TODO(jaewan): Add sanity check (b/73863865)
mUid = uid;
mType = type;
@@ -168,15 +168,15 @@
return mType;
}
- public String getServiceName() {
+ String getServiceName() {
return mServiceName;
}
- public IMediaSession2 getSessionBinder() {
+ IMediaSession2 getSessionBinder() {
return mSessionBinder;
}
- public static SessionToken2 fromBundle_impl(Context context, Bundle bundle) {
+ public static SessionToken2 fromBundle_impl(Bundle bundle) {
if (bundle == null) {
return null;
}
@@ -207,7 +207,7 @@
if (TextUtils.isEmpty(packageName) || id == null) {
throw new IllegalArgumentException("Package name nor ID cannot be null.");
}
- return new SessionToken2Impl(context, uid, type, packageName, serviceName, id,
+ return new SessionToken2Impl(uid, type, packageName, serviceName, id,
sessionBinder != null ? IMediaSession2.Stub.asInterface(sessionBinder) : null)
.getInstance();
}
@@ -254,7 +254,7 @@
+ " service=" + mServiceName + " binder=" + mSessionBinder + "}";
}
- public static SessionToken2Impl from(SessionToken2 token) {
+ static SessionToken2Impl from(SessionToken2 token) {
return ((SessionToken2Impl) token.getProvider());
}
}
diff --git a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
index 156bcae..bf22e1b 100644
--- a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
@@ -19,13 +19,10 @@
import static android.media.VolumeProvider2.VOLUME_CONTROL_FIXED;
import static android.media.VolumeProvider2.VOLUME_CONTROL_RELATIVE;
-import android.content.Context;
import android.media.VolumeProvider2;
import android.media.update.VolumeProvider2Provider;
public class VolumeProvider2Impl implements VolumeProvider2Provider {
-
- private final Context mContext;
private final VolumeProvider2 mInstance;
private final int mControlType;
private final int mMaxVolume;
@@ -33,7 +30,7 @@
private int mCurrentVolume;
private Callback mCallback;
- public VolumeProvider2Impl(Context context, VolumeProvider2 instance,
+ public VolumeProvider2Impl(VolumeProvider2 instance,
@VolumeProvider2.ControlType int controlType, int maxVolume, int currentVolume) {
if (controlType != VOLUME_CONTROL_FIXED && controlType != VOLUME_CONTROL_RELATIVE
&& controlType != VOLUME_CONTROL_ABSOLUTE) {
@@ -47,7 +44,6 @@
throw new IllegalArgumentException("currentVolume shouldn't be greater than maxVolume"
+ ", maxVolume=" + maxVolume + ", currentVolume=" + currentVolume);
}
- mContext = context;
mInstance = instance;
mControlType = controlType;
mMaxVolume = maxVolume;
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/ClosedCaptionRenderer.java b/packages/MediaComponents/src/com/android/media/subtitle/ClosedCaptionRenderer.java
new file mode 100644
index 0000000..ff7eec9
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/subtitle/ClosedCaptionRenderer.java
@@ -0,0 +1,1501 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media.subtitle;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.media.MediaFormat;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+import android.text.style.StyleSpan;
+import android.text.style.UnderlineSpan;
+import android.text.style.UpdateAppearance;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Vector;
+
+// Note: This is forked from android.media.ClosedCaptionRenderer since P
+public class ClosedCaptionRenderer extends SubtitleController.Renderer {
+ private final Context mContext;
+ private Cea608CCWidget mCCWidget;
+
+ public ClosedCaptionRenderer(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ return MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ if (MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType)) {
+ if (mCCWidget == null) {
+ mCCWidget = new Cea608CCWidget(mContext);
+ }
+ return new Cea608CaptionTrack(mCCWidget, format);
+ }
+ throw new RuntimeException("No matching format: " + format.toString());
+ }
+}
+
+class Cea608CaptionTrack extends SubtitleTrack {
+ private final Cea608CCParser mCCParser;
+ private final Cea608CCWidget mRenderingWidget;
+
+ Cea608CaptionTrack(Cea608CCWidget renderingWidget, MediaFormat format) {
+ super(format);
+
+ mRenderingWidget = renderingWidget;
+ mCCParser = new Cea608CCParser(mRenderingWidget);
+ }
+
+ @Override
+ public void onData(byte[] data, boolean eos, long runID) {
+ mCCParser.parse(data);
+ }
+
+ @Override
+ public RenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
+ }
+
+ @Override
+ public void updateView(Vector<Cue> activeCues) {
+ // Overriding with NO-OP, CC rendering by-passes this
+ }
+}
+
+/**
+ * Abstract widget class to render a closed caption track.
+ */
+abstract class ClosedCaptionWidget extends ViewGroup implements SubtitleTrack.RenderingWidget {
+
+ interface ClosedCaptionLayout {
+ void setCaptionStyle(CaptionStyle captionStyle);
+ void setFontScale(float scale);
+ }
+
+ private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
+
+ /** Captioning manager, used to obtain and track caption properties. */
+ private final CaptioningManager mManager;
+
+ /** Current caption style. */
+ protected CaptionStyle mCaptionStyle;
+
+ /** Callback for rendering changes. */
+ protected OnChangedListener mListener;
+
+ /** Concrete layout of CC. */
+ protected ClosedCaptionLayout mClosedCaptionLayout;
+
+ /** Whether a caption style change listener is registered. */
+ private boolean mHasChangeListener;
+
+ public ClosedCaptionWidget(Context context) {
+ this(context, null);
+ }
+
+ public ClosedCaptionWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle());
+
+ mClosedCaptionLayout = createCaptionLayout(context);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ mClosedCaptionLayout.setFontScale(mManager.getFontScale());
+ addView((ViewGroup) mClosedCaptionLayout, LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT);
+
+ requestLayout();
+ }
+
+ public abstract ClosedCaptionLayout createCaptionLayout(Context context);
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ ((ViewGroup) mClosedCaptionLayout).measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ ((ViewGroup) mClosedCaptionLayout).layout(l, t, r, b);
+ }
+
+ /**
+ * Manages whether this renderer is listening for caption style changes.
+ */
+ private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+ @Override
+ public void onUserStyleChanged(CaptionStyle userStyle) {
+ mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ }
+
+ @Override
+ public void onFontScaleChanged(float fontScale) {
+ mClosedCaptionLayout.setFontScale(fontScale);
+ }
+ };
+
+ private void manageChangeListener() {
+ final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+ if (mHasChangeListener != needsListener) {
+ mHasChangeListener = needsListener;
+
+ if (needsListener) {
+ mManager.addCaptioningChangeListener(mCaptioningListener);
+ } else {
+ mManager.removeCaptioningChangeListener(mCaptioningListener);
+ }
+ }
+ }
+}
+
+/**
+ * CCParser processes CEA-608 closed caption data.
+ *
+ * It calls back into OnDisplayChangedListener upon
+ * display change with styled text for rendering.
+ *
+ */
+class Cea608CCParser {
+ public static final int MAX_ROWS = 15;
+ public static final int MAX_COLS = 32;
+
+ private static final String TAG = "Cea608CCParser";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final int INVALID = -1;
+
+ // EIA-CEA-608: Table 70 - Control Codes
+ private static final int RCL = 0x20;
+ private static final int BS = 0x21;
+ private static final int AOF = 0x22;
+ private static final int AON = 0x23;
+ private static final int DER = 0x24;
+ private static final int RU2 = 0x25;
+ private static final int RU3 = 0x26;
+ private static final int RU4 = 0x27;
+ private static final int FON = 0x28;
+ private static final int RDC = 0x29;
+ private static final int TR = 0x2a;
+ private static final int RTD = 0x2b;
+ private static final int EDM = 0x2c;
+ private static final int CR = 0x2d;
+ private static final int ENM = 0x2e;
+ private static final int EOC = 0x2f;
+
+ // Transparent Space
+ private static final char TS = '\u00A0';
+
+ // Captioning Modes
+ private static final int MODE_UNKNOWN = 0;
+ private static final int MODE_PAINT_ON = 1;
+ private static final int MODE_ROLL_UP = 2;
+ private static final int MODE_POP_ON = 3;
+ private static final int MODE_TEXT = 4;
+
+ private final DisplayListener mListener;
+
+ private int mMode = MODE_PAINT_ON;
+ private int mRollUpSize = 4;
+ private int mPrevCtrlCode = INVALID;
+
+ private CCMemory mDisplay = new CCMemory();
+ private CCMemory mNonDisplay = new CCMemory();
+ private CCMemory mTextMem = new CCMemory();
+
+ Cea608CCParser(DisplayListener listener) {
+ mListener = listener;
+ }
+
+ public void parse(byte[] data) {
+ CCData[] ccData = CCData.fromByteArray(data);
+
+ for (int i = 0; i < ccData.length; i++) {
+ if (DEBUG) {
+ Log.d(TAG, ccData[i].toString());
+ }
+
+ if (handleCtrlCode(ccData[i])
+ || handleTabOffsets(ccData[i])
+ || handlePACCode(ccData[i])
+ || handleMidRowCode(ccData[i])) {
+ continue;
+ }
+
+ handleDisplayableChars(ccData[i]);
+ }
+ }
+
+ interface DisplayListener {
+ void onDisplayChanged(SpannableStringBuilder[] styledTexts);
+ CaptionStyle getCaptionStyle();
+ }
+
+ private CCMemory getMemory() {
+ // get the CC memory to operate on for current mode
+ switch (mMode) {
+ case MODE_POP_ON:
+ return mNonDisplay;
+ case MODE_TEXT:
+ // TODO(chz): support only caption mode for now,
+ // in text mode, dump everything to text mem.
+ return mTextMem;
+ case MODE_PAINT_ON:
+ case MODE_ROLL_UP:
+ return mDisplay;
+ default:
+ Log.w(TAG, "unrecoginized mode: " + mMode);
+ }
+ return mDisplay;
+ }
+
+ private boolean handleDisplayableChars(CCData ccData) {
+ if (!ccData.isDisplayableChar()) {
+ return false;
+ }
+
+ // Extended char includes 1 automatic backspace
+ if (ccData.isExtendedChar()) {
+ getMemory().bs();
+ }
+
+ getMemory().writeText(ccData.getDisplayText());
+
+ if (mMode == MODE_PAINT_ON || mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+
+ return true;
+ }
+
+ private boolean handleMidRowCode(CCData ccData) {
+ StyleCode m = ccData.getMidRow();
+ if (m != null) {
+ getMemory().writeMidRowCode(m);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean handlePACCode(CCData ccData) {
+ PAC pac = ccData.getPAC();
+
+ if (pac != null) {
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().moveBaselineTo(pac.getRow(), mRollUpSize);
+ }
+ getMemory().writePAC(pac);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleTabOffsets(CCData ccData) {
+ int tabs = ccData.getTabOffset();
+
+ if (tabs > 0) {
+ getMemory().tab(tabs);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleCtrlCode(CCData ccData) {
+ int ctrlCode = ccData.getCtrlCode();
+
+ if (mPrevCtrlCode != INVALID && mPrevCtrlCode == ctrlCode) {
+ // discard double ctrl codes (but if there's a 3rd one, we still take that)
+ mPrevCtrlCode = INVALID;
+ return true;
+ }
+
+ switch(ctrlCode) {
+ case RCL:
+ // select pop-on style
+ mMode = MODE_POP_ON;
+ break;
+ case BS:
+ getMemory().bs();
+ break;
+ case DER:
+ getMemory().der();
+ break;
+ case RU2:
+ case RU3:
+ case RU4:
+ mRollUpSize = (ctrlCode - 0x23);
+ // erase memory if currently in other style
+ if (mMode != MODE_ROLL_UP) {
+ mDisplay.erase();
+ mNonDisplay.erase();
+ }
+ // select roll-up style
+ mMode = MODE_ROLL_UP;
+ break;
+ case FON:
+ Log.i(TAG, "Flash On");
+ break;
+ case RDC:
+ // select paint-on style
+ mMode = MODE_PAINT_ON;
+ break;
+ case TR:
+ mMode = MODE_TEXT;
+ mTextMem.erase();
+ break;
+ case RTD:
+ mMode = MODE_TEXT;
+ break;
+ case EDM:
+ // erase display memory
+ mDisplay.erase();
+ updateDisplay();
+ break;
+ case CR:
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().rollUp(mRollUpSize);
+ } else {
+ getMemory().cr();
+ }
+ if (mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+ break;
+ case ENM:
+ // erase non-display memory
+ mNonDisplay.erase();
+ break;
+ case EOC:
+ // swap display/non-display memory
+ swapMemory();
+ // switch to pop-on style
+ mMode = MODE_POP_ON;
+ updateDisplay();
+ break;
+ case INVALID:
+ default:
+ mPrevCtrlCode = INVALID;
+ return false;
+ }
+
+ mPrevCtrlCode = ctrlCode;
+
+ // handled
+ return true;
+ }
+
+ private void updateDisplay() {
+ if (mListener != null) {
+ CaptionStyle captionStyle = mListener.getCaptionStyle();
+ mListener.onDisplayChanged(mDisplay.getStyledText(captionStyle));
+ }
+ }
+
+ private void swapMemory() {
+ CCMemory temp = mDisplay;
+ mDisplay = mNonDisplay;
+ mNonDisplay = temp;
+ }
+
+ private static class StyleCode {
+ static final int COLOR_WHITE = 0;
+ static final int COLOR_GREEN = 1;
+ static final int COLOR_BLUE = 2;
+ static final int COLOR_CYAN = 3;
+ static final int COLOR_RED = 4;
+ static final int COLOR_YELLOW = 5;
+ static final int COLOR_MAGENTA = 6;
+ static final int COLOR_INVALID = 7;
+
+ static final int STYLE_ITALICS = 0x00000001;
+ static final int STYLE_UNDERLINE = 0x00000002;
+
+ static final String[] mColorMap = {
+ "WHITE", "GREEN", "BLUE", "CYAN", "RED", "YELLOW", "MAGENTA", "INVALID"
+ };
+
+ final int mStyle;
+ final int mColor;
+
+ static StyleCode fromByte(byte data2) {
+ int style = 0;
+ int color = (data2 >> 1) & 0x7;
+
+ if ((data2 & 0x1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+
+ return new StyleCode(style, color);
+ }
+
+ StyleCode(int style, int color) {
+ mStyle = style;
+ mColor = color;
+ }
+
+ boolean isItalics() {
+ return (mStyle & STYLE_ITALICS) != 0;
+ }
+
+ boolean isUnderline() {
+ return (mStyle & STYLE_UNDERLINE) != 0;
+ }
+
+ int getColor() {
+ return mColor;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append("{");
+ str.append(mColorMap[mColor]);
+ if ((mStyle & STYLE_ITALICS) != 0) {
+ str.append(", ITALICS");
+ }
+ if ((mStyle & STYLE_UNDERLINE) != 0) {
+ str.append(", UNDERLINE");
+ }
+ str.append("}");
+
+ return str.toString();
+ }
+ }
+
+ private static class PAC extends StyleCode {
+ final int mRow;
+ final int mCol;
+
+ static PAC fromBytes(byte data1, byte data2) {
+ int[] rowTable = {11, 1, 3, 12, 14, 5, 7, 9};
+ int row = rowTable[data1 & 0x07] + ((data2 & 0x20) >> 5);
+ int style = 0;
+ if ((data2 & 1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+ if ((data2 & 0x10) != 0) {
+ // indent code
+ int indent = (data2 >> 1) & 0x7;
+ return new PAC(row, indent * 4, style, COLOR_WHITE);
+ } else {
+ // style code
+ int color = (data2 >> 1) & 0x7;
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+ return new PAC(row, -1, style, color);
+ }
+ }
+
+ PAC(int row, int col, int style, int color) {
+ super(style, color);
+ mRow = row;
+ mCol = col;
+ }
+
+ boolean isIndentPAC() {
+ return (mCol >= 0);
+ }
+
+ int getRow() {
+ return mRow;
+ }
+
+ int getCol() {
+ return mCol;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{%d, %d}, %s",
+ mRow, mCol, super.toString());
+ }
+ }
+
+ /**
+ * Mutable version of BackgroundSpan to facilitate text rendering with edge styles.
+ */
+ public static class MutableBackgroundColorSpan extends CharacterStyle
+ implements UpdateAppearance {
+ private int mColor;
+
+ public MutableBackgroundColorSpan(int color) {
+ mColor = color;
+ }
+
+ public void setBackgroundColor(int color) {
+ mColor = color;
+ }
+
+ public int getBackgroundColor() {
+ return mColor;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ ds.bgColor = mColor;
+ }
+ }
+
+ /* CCLineBuilder keeps track of displayable chars, as well as
+ * MidRow styles and PACs, for a single line of CC memory.
+ *
+ * It generates styled text via getStyledText() method.
+ */
+ private static class CCLineBuilder {
+ private final StringBuilder mDisplayChars;
+ private final StyleCode[] mMidRowStyles;
+ private final StyleCode[] mPACStyles;
+
+ CCLineBuilder(String str) {
+ mDisplayChars = new StringBuilder(str);
+ mMidRowStyles = new StyleCode[mDisplayChars.length()];
+ mPACStyles = new StyleCode[mDisplayChars.length()];
+ }
+
+ void setCharAt(int index, char ch) {
+ mDisplayChars.setCharAt(index, ch);
+ mMidRowStyles[index] = null;
+ }
+
+ void setMidRowAt(int index, StyleCode m) {
+ mDisplayChars.setCharAt(index, ' ');
+ mMidRowStyles[index] = m;
+ }
+
+ void setPACAt(int index, PAC pac) {
+ mPACStyles[index] = pac;
+ }
+
+ char charAt(int index) {
+ return mDisplayChars.charAt(index);
+ }
+
+ int length() {
+ return mDisplayChars.length();
+ }
+
+ void applyStyleSpan(
+ SpannableStringBuilder styledText,
+ StyleCode s, int start, int end) {
+ if (s.isItalics()) {
+ styledText.setSpan(
+ new StyleSpan(android.graphics.Typeface.ITALIC),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ if (s.isUnderline()) {
+ styledText.setSpan(
+ new UnderlineSpan(),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ SpannableStringBuilder getStyledText(CaptionStyle captionStyle) {
+ SpannableStringBuilder styledText = new SpannableStringBuilder(mDisplayChars);
+ int start = -1, next = 0;
+ int styleStart = -1;
+ StyleCode curStyle = null;
+ while (next < mDisplayChars.length()) {
+ StyleCode newStyle = null;
+ if (mMidRowStyles[next] != null) {
+ // apply mid-row style change
+ newStyle = mMidRowStyles[next];
+ } else if (mPACStyles[next] != null
+ && (styleStart < 0 || start < 0)) {
+ // apply PAC style change, only if:
+ // 1. no style set, or
+ // 2. style set, but prev char is none-displayable
+ newStyle = mPACStyles[next];
+ }
+ if (newStyle != null) {
+ curStyle = newStyle;
+ if (styleStart >= 0 && start >= 0) {
+ applyStyleSpan(styledText, newStyle, styleStart, next);
+ }
+ styleStart = next;
+ }
+
+ if (mDisplayChars.charAt(next) != TS) {
+ if (start < 0) {
+ start = next;
+ }
+ } else if (start >= 0) {
+ int expandedStart = mDisplayChars.charAt(start) == ' ' ? start : start - 1;
+ int expandedEnd = mDisplayChars.charAt(next - 1) == ' ' ? next : next + 1;
+ styledText.setSpan(
+ new MutableBackgroundColorSpan(captionStyle.backgroundColor),
+ expandedStart, expandedEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ if (styleStart >= 0) {
+ applyStyleSpan(styledText, curStyle, styleStart, expandedEnd);
+ }
+ start = -1;
+ }
+ next++;
+ }
+
+ return styledText;
+ }
+ }
+
+ /*
+ * CCMemory models a console-style display.
+ */
+ private static class CCMemory {
+ private final String mBlankLine;
+ private final CCLineBuilder[] mLines = new CCLineBuilder[MAX_ROWS + 2];
+ private int mRow;
+ private int mCol;
+
+ CCMemory() {
+ char[] blank = new char[MAX_COLS + 2];
+ Arrays.fill(blank, TS);
+ mBlankLine = new String(blank);
+ }
+
+ void erase() {
+ // erase all lines
+ for (int i = 0; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ mRow = MAX_ROWS;
+ mCol = 1;
+ }
+
+ void der() {
+ if (mLines[mRow] != null) {
+ for (int i = 0; i < mCol; i++) {
+ if (mLines[mRow].charAt(i) != TS) {
+ for (int j = mCol; j < mLines[mRow].length(); j++) {
+ mLines[j].setCharAt(j, TS);
+ }
+ return;
+ }
+ }
+ mLines[mRow] = null;
+ }
+ }
+
+ void tab(int tabs) {
+ moveCursorByCol(tabs);
+ }
+
+ void bs() {
+ moveCursorByCol(-1);
+ if (mLines[mRow] != null) {
+ mLines[mRow].setCharAt(mCol, TS);
+ if (mCol == MAX_COLS - 1) {
+ // Spec recommendation:
+ // if cursor was at col 32, move cursor
+ // back to col 31 and erase both col 31&32
+ mLines[mRow].setCharAt(MAX_COLS, TS);
+ }
+ }
+ }
+
+ void cr() {
+ moveCursorTo(mRow + 1, 1);
+ }
+
+ void rollUp(int windowSize) {
+ int i;
+ for (i = 0; i <= mRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ int startRow = mRow - windowSize + 1;
+ if (startRow < 1) {
+ startRow = 1;
+ }
+ for (i = startRow; i < mRow; i++) {
+ mLines[i] = mLines[i + 1];
+ }
+ for (i = mRow; i < mLines.length; i++) {
+ // clear base row
+ mLines[i] = null;
+ }
+ // default to col 1, in case PAC is not sent
+ mCol = 1;
+ }
+
+ void writeText(String text) {
+ for (int i = 0; i < text.length(); i++) {
+ getLineBuffer(mRow).setCharAt(mCol, text.charAt(i));
+ moveCursorByCol(1);
+ }
+ }
+
+ void writeMidRowCode(StyleCode m) {
+ getLineBuffer(mRow).setMidRowAt(mCol, m);
+ moveCursorByCol(1);
+ }
+
+ void writePAC(PAC pac) {
+ if (pac.isIndentPAC()) {
+ moveCursorTo(pac.getRow(), pac.getCol());
+ } else {
+ moveCursorTo(pac.getRow(), 1);
+ }
+ getLineBuffer(mRow).setPACAt(mCol, pac);
+ }
+
+ SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) {
+ ArrayList<SpannableStringBuilder> rows = new ArrayList<>(MAX_ROWS);
+ for (int i = 1; i <= MAX_ROWS; i++) {
+ rows.add(mLines[i] != null ?
+ mLines[i].getStyledText(captionStyle) : null);
+ }
+ return rows.toArray(new SpannableStringBuilder[MAX_ROWS]);
+ }
+
+ private static int clamp(int x, int min, int max) {
+ return x < min ? min : (x > max ? max : x);
+ }
+
+ private void moveCursorTo(int row, int col) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ mCol = clamp(col, 1, MAX_COLS);
+ }
+
+ private void moveCursorToRow(int row) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ }
+
+ private void moveCursorByCol(int col) {
+ mCol = clamp(mCol + col, 1, MAX_COLS);
+ }
+
+ private void moveBaselineTo(int baseRow, int windowSize) {
+ if (mRow == baseRow) {
+ return;
+ }
+ int actualWindowSize = windowSize;
+ if (baseRow < actualWindowSize) {
+ actualWindowSize = baseRow;
+ }
+ if (mRow < actualWindowSize) {
+ actualWindowSize = mRow;
+ }
+
+ int i;
+ if (baseRow < mRow) {
+ // copy from bottom to top row
+ for (i = actualWindowSize - 1; i >= 0; i--) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ } else {
+ // copy from top to bottom row
+ for (i = 0; i < actualWindowSize; i++) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ }
+ // clear rest of the rows
+ for (i = 0; i <= baseRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ for (i = baseRow + 1; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ }
+
+ private CCLineBuilder getLineBuffer(int row) {
+ if (mLines[row] == null) {
+ mLines[row] = new CCLineBuilder(mBlankLine);
+ }
+ return mLines[row];
+ }
+ }
+
+ /*
+ * CCData parses the raw CC byte pair into displayable chars,
+ * misc control codes, Mid-Row or Preamble Address Codes.
+ */
+ private static class CCData {
+ private final byte mType;
+ private final byte mData1;
+ private final byte mData2;
+
+ private static final String[] mCtrlCodeMap = {
+ "RCL", "BS" , "AOF", "AON",
+ "DER", "RU2", "RU3", "RU4",
+ "FON", "RDC", "TR" , "RTD",
+ "EDM", "CR" , "ENM", "EOC",
+ };
+
+ private static final String[] mSpecialCharMap = {
+ "\u00AE",
+ "\u00B0",
+ "\u00BD",
+ "\u00BF",
+ "\u2122",
+ "\u00A2",
+ "\u00A3",
+ "\u266A", // Eighth note
+ "\u00E0",
+ "\u00A0", // Transparent space
+ "\u00E8",
+ "\u00E2",
+ "\u00EA",
+ "\u00EE",
+ "\u00F4",
+ "\u00FB",
+ };
+
+ private static final String[] mSpanishCharMap = {
+ // Spanish and misc chars
+ "\u00C1", // A
+ "\u00C9", // E
+ "\u00D3", // I
+ "\u00DA", // O
+ "\u00DC", // U
+ "\u00FC", // u
+ "\u2018", // opening single quote
+ "\u00A1", // inverted exclamation mark
+ "*",
+ "'",
+ "\u2014", // em dash
+ "\u00A9", // Copyright
+ "\u2120", // Servicemark
+ "\u2022", // round bullet
+ "\u201C", // opening double quote
+ "\u201D", // closing double quote
+ // French
+ "\u00C0",
+ "\u00C2",
+ "\u00C7",
+ "\u00C8",
+ "\u00CA",
+ "\u00CB",
+ "\u00EB",
+ "\u00CE",
+ "\u00CF",
+ "\u00EF",
+ "\u00D4",
+ "\u00D9",
+ "\u00F9",
+ "\u00DB",
+ "\u00AB",
+ "\u00BB"
+ };
+
+ private static final String[] mProtugueseCharMap = {
+ // Portuguese
+ "\u00C3",
+ "\u00E3",
+ "\u00CD",
+ "\u00CC",
+ "\u00EC",
+ "\u00D2",
+ "\u00F2",
+ "\u00D5",
+ "\u00F5",
+ "{",
+ "}",
+ "\\",
+ "^",
+ "_",
+ "|",
+ "~",
+ // German and misc chars
+ "\u00C4",
+ "\u00E4",
+ "\u00D6",
+ "\u00F6",
+ "\u00DF",
+ "\u00A5",
+ "\u00A4",
+ "\u2502", // vertical bar
+ "\u00C5",
+ "\u00E5",
+ "\u00D8",
+ "\u00F8",
+ "\u250C", // top-left corner
+ "\u2510", // top-right corner
+ "\u2514", // lower-left corner
+ "\u2518", // lower-right corner
+ };
+
+ static CCData[] fromByteArray(byte[] data) {
+ CCData[] ccData = new CCData[data.length / 3];
+
+ for (int i = 0; i < ccData.length; i++) {
+ ccData[i] = new CCData(
+ data[i * 3],
+ data[i * 3 + 1],
+ data[i * 3 + 2]);
+ }
+
+ return ccData;
+ }
+
+ CCData(byte type, byte data1, byte data2) {
+ mType = type;
+ mData1 = data1;
+ mData2 = data2;
+ }
+
+ int getCtrlCode() {
+ if ((mData1 == 0x14 || mData1 == 0x1c)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return mData2;
+ }
+ return INVALID;
+ }
+
+ StyleCode getMidRow() {
+ // only support standard Mid-row codes, ignore
+ // optional background/foreground mid-row codes
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return StyleCode.fromByte(mData2);
+ }
+ return null;
+ }
+
+ PAC getPAC() {
+ if ((mData1 & 0x70) == 0x10
+ && (mData2 & 0x40) == 0x40
+ && ((mData1 & 0x07) != 0 || (mData2 & 0x20) == 0)) {
+ return PAC.fromBytes(mData1, mData2);
+ }
+ return null;
+ }
+
+ int getTabOffset() {
+ if ((mData1 == 0x17 || mData1 == 0x1f)
+ && mData2 >= 0x21 && mData2 <= 0x23) {
+ return mData2 & 0x3;
+ }
+ return 0;
+ }
+
+ boolean isDisplayableChar() {
+ return isBasicChar() || isSpecialChar() || isExtendedChar();
+ }
+
+ String getDisplayText() {
+ String str = getBasicChars();
+
+ if (str == null) {
+ str = getSpecialChar();
+
+ if (str == null) {
+ str = getExtendedChar();
+ }
+ }
+
+ return str;
+ }
+
+ private String ctrlCodeToString(int ctrlCode) {
+ return mCtrlCodeMap[ctrlCode - 0x20];
+ }
+
+ private boolean isBasicChar() {
+ return mData1 >= 0x20 && mData1 <= 0x7f;
+ }
+
+ private boolean isSpecialChar() {
+ return ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f);
+ }
+
+ private boolean isExtendedChar() {
+ return ((mData1 == 0x12 || mData1 == 0x1A
+ || mData1 == 0x13 || mData1 == 0x1B)
+ && mData2 >= 0x20 && mData2 <= 0x3f);
+ }
+
+ private char getBasicChar(byte data) {
+ char c;
+ // replace the non-ASCII ones
+ switch (data) {
+ case 0x2A: c = '\u00E1'; break;
+ case 0x5C: c = '\u00E9'; break;
+ case 0x5E: c = '\u00ED'; break;
+ case 0x5F: c = '\u00F3'; break;
+ case 0x60: c = '\u00FA'; break;
+ case 0x7B: c = '\u00E7'; break;
+ case 0x7C: c = '\u00F7'; break;
+ case 0x7D: c = '\u00D1'; break;
+ case 0x7E: c = '\u00F1'; break;
+ case 0x7F: c = '\u2588'; break; // Full block
+ default: c = (char) data; break;
+ }
+ return c;
+ }
+
+ private String getBasicChars() {
+ if (mData1 >= 0x20 && mData1 <= 0x7f) {
+ StringBuilder builder = new StringBuilder(2);
+ builder.append(getBasicChar(mData1));
+ if (mData2 >= 0x20 && mData2 <= 0x7f) {
+ builder.append(getBasicChar(mData2));
+ }
+ return builder.toString();
+ }
+
+ return null;
+ }
+
+ private String getSpecialChar() {
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f) {
+ return mSpecialCharMap[mData2 - 0x30];
+ }
+
+ return null;
+ }
+
+ private String getExtendedChar() {
+ if ((mData1 == 0x12 || mData1 == 0x1A)
+ && mData2 >= 0x20 && mData2 <= 0x3f){
+ // 1 Spanish/French char
+ return mSpanishCharMap[mData2 - 0x20];
+ } else if ((mData1 == 0x13 || mData1 == 0x1B)
+ && mData2 >= 0x20 && mData2 <= 0x3f){
+ // 1 Portuguese/German/Danish char
+ return mProtugueseCharMap[mData2 - 0x20];
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ String str;
+
+ if (mData1 < 0x10 && mData2 < 0x10) {
+ // Null Pad, ignore
+ return String.format("[%d]Null: %02x %02x", mType, mData1, mData2);
+ }
+
+ int ctrlCode = getCtrlCode();
+ if (ctrlCode != INVALID) {
+ return String.format("[%d]%s", mType, ctrlCodeToString(ctrlCode));
+ }
+
+ int tabOffset = getTabOffset();
+ if (tabOffset > 0) {
+ return String.format("[%d]Tab%d", mType, tabOffset);
+ }
+
+ PAC pac = getPAC();
+ if (pac != null) {
+ return String.format("[%d]PAC: %s", mType, pac.toString());
+ }
+
+ StyleCode m = getMidRow();
+ if (m != null) {
+ return String.format("[%d]Mid-row: %s", mType, m.toString());
+ }
+
+ if (isDisplayableChar()) {
+ return String.format("[%d]Displayable: %s (%02x %02x)",
+ mType, getDisplayText(), mData1, mData2);
+ }
+
+ return String.format("[%d]Invalid: %02x %02x", mType, mData1, mData2);
+ }
+ }
+}
+
+/**
+ * Widget capable of rendering CEA-608 closed captions.
+ */
+class Cea608CCWidget extends ClosedCaptionWidget implements Cea608CCParser.DisplayListener {
+ private static final Rect mTextBounds = new Rect();
+ private static final String mDummyText = "1234567890123456789012345678901234";
+
+ public Cea608CCWidget(Context context) {
+ this(context, null);
+ }
+
+ public Cea608CCWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public Cea608CCWidget(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ public Cea608CCWidget(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public ClosedCaptionLayout createCaptionLayout(Context context) {
+ return new CCLayout(context);
+ }
+
+ @Override
+ public void onDisplayChanged(SpannableStringBuilder[] styledTexts) {
+ ((CCLayout) mClosedCaptionLayout).update(styledTexts);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+
+ @Override
+ public CaptionStyle getCaptionStyle() {
+ return mCaptionStyle;
+ }
+
+ private static class CCLineBox extends TextView {
+ private static final float FONT_PADDING_RATIO = 0.75f;
+ private static final float EDGE_OUTLINE_RATIO = 0.1f;
+ private static final float EDGE_SHADOW_RATIO = 0.05f;
+ private float mOutlineWidth;
+ private float mShadowRadius;
+ private float mShadowOffset;
+
+ private int mTextColor = Color.WHITE;
+ private int mBgColor = Color.BLACK;
+ private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
+ private int mEdgeColor = Color.TRANSPARENT;
+
+ CCLineBox(Context context) {
+ super(context);
+ setGravity(Gravity.CENTER);
+ setBackgroundColor(Color.TRANSPARENT);
+ setTextColor(Color.WHITE);
+ setTypeface(Typeface.MONOSPACE);
+ setVisibility(View.INVISIBLE);
+
+ final Resources res = getContext().getResources();
+
+ // get the default (will be updated later during measure)
+ mOutlineWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_outline_width);
+ mShadowRadius = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_shadow_radius);
+ mShadowOffset = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_shadow_offset);
+ }
+
+ void setCaptionStyle(CaptionStyle captionStyle) {
+ mTextColor = captionStyle.foregroundColor;
+ mBgColor = captionStyle.backgroundColor;
+ mEdgeType = captionStyle.edgeType;
+ mEdgeColor = captionStyle.edgeColor;
+
+ setTextColor(mTextColor);
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor);
+ } else {
+ setShadowLayer(0, 0, 0, 0);
+ }
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ float fontSize = MeasureSpec.getSize(heightMeasureSpec) * FONT_PADDING_RATIO;
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
+
+ mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f;
+ mShadowRadius = EDGE_SHADOW_RATIO * fontSize + 1.0f;;
+ mShadowOffset = mShadowRadius;
+
+ // set font scale in the X direction to match the required width
+ setScaleX(1.0f);
+ getPaint().getTextBounds(mDummyText, 0, mDummyText.length(), mTextBounds);
+ float actualTextWidth = mTextBounds.width();
+ float requiredTextWidth = MeasureSpec.getSize(widthMeasureSpec);
+ setScaleX(requiredTextWidth / actualTextWidth);
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onDraw(Canvas c) {
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_UNSPECIFIED
+ || mEdgeType == CaptionStyle.EDGE_TYPE_NONE
+ || mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ // these edge styles don't require a second pass
+ super.onDraw(c);
+ return;
+ }
+
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+ drawEdgeOutline(c);
+ } else {
+ // Raised or depressed
+ drawEdgeRaisedOrDepressed(c);
+ }
+ }
+
+ private void drawEdgeOutline(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ Paint.Join previousJoin = textPaint.getStrokeJoin();
+ float previousWidth = textPaint.getStrokeWidth();
+
+ setTextColor(mEdgeColor);
+ textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ textPaint.setStrokeJoin(Paint.Join.ROUND);
+ textPaint.setStrokeWidth(mOutlineWidth);
+
+ // Draw outline and background only.
+ super.onDraw(c);
+
+ // Restore original settings.
+ setTextColor(mTextColor);
+ textPaint.setStyle(previousStyle);
+ textPaint.setStrokeJoin(previousJoin);
+ textPaint.setStrokeWidth(previousWidth);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+ // Draw foreground only.
+ super.onDraw(c);
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ private void drawEdgeRaisedOrDepressed(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ textPaint.setStyle(Paint.Style.FILL);
+
+ final boolean raised = mEdgeType == CaptionStyle.EDGE_TYPE_RAISED;
+ final int colorUp = raised ? Color.WHITE : mEdgeColor;
+ final int colorDown = raised ? mEdgeColor : Color.WHITE;
+ final float offset = mShadowRadius / 2f;
+
+ // Draw background and text with shadow up
+ setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
+ super.onDraw(c);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+
+ // Draw text with shadow down
+ setShadowLayer(mShadowRadius, +offset, +offset, colorDown);
+ super.onDraw(c);
+
+ // Restore settings
+ textPaint.setStyle(previousStyle);
+
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ private void setBackgroundSpans(int color) {
+ CharSequence text = getText();
+ if (text instanceof Spannable) {
+ Spannable spannable = (Spannable) text;
+ Cea608CCParser.MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
+ 0, spannable.length(), Cea608CCParser.MutableBackgroundColorSpan.class);
+ for (int i = 0; i < bgSpans.length; i++) {
+ bgSpans[i].setBackgroundColor(color);
+ }
+ }
+ }
+ }
+
+ private static class CCLayout extends LinearLayout implements ClosedCaptionLayout {
+ private static final int MAX_ROWS = Cea608CCParser.MAX_ROWS;
+ private static final float SAFE_AREA_RATIO = 0.9f;
+
+ private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS];
+
+ CCLayout(Context context) {
+ super(context);
+ setGravity(Gravity.START);
+ setOrientation(LinearLayout.VERTICAL);
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i] = new CCLineBox(getContext());
+ addView(mLineBoxes[i], LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ @Override
+ public void setCaptionStyle(CaptionStyle captionStyle) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].setCaptionStyle(captionStyle);
+ }
+ }
+
+ @Override
+ public void setFontScale(float fontScale) {
+ // Ignores the font scale changes of the system wide CC preference.
+ }
+
+ void update(SpannableStringBuilder[] textBuffer) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ if (textBuffer[i] != null) {
+ mLineBoxes[i].setText(textBuffer[i], TextView.BufferType.SPANNABLE);
+ mLineBoxes[i].setVisibility(View.VISIBLE);
+ } else {
+ mLineBoxes[i].setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int safeWidth = getMeasuredWidth();
+ int safeHeight = getMeasuredHeight();
+
+ // CEA-608 assumes 4:3 video
+ if (safeWidth * 3 >= safeHeight * 4) {
+ safeWidth = safeHeight * 4 / 3;
+ } else {
+ safeHeight = safeWidth * 3 / 4;
+ }
+ safeWidth *= SAFE_AREA_RATIO;
+ safeHeight *= SAFE_AREA_RATIO;
+
+ int lineHeight = safeHeight / MAX_ROWS;
+ int lineHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ lineHeight, MeasureSpec.EXACTLY);
+ int lineWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ safeWidth, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].measure(lineWidthMeasureSpec, lineHeightMeasureSpec);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // safe caption area
+ int viewPortWidth = r - l;
+ int viewPortHeight = b - t;
+ int safeWidth, safeHeight;
+ // CEA-608 assumes 4:3 video
+ if (viewPortWidth * 3 >= viewPortHeight * 4) {
+ safeWidth = viewPortHeight * 4 / 3;
+ safeHeight = viewPortHeight;
+ } else {
+ safeWidth = viewPortWidth;
+ safeHeight = viewPortWidth * 3 / 4;
+ }
+ safeWidth *= SAFE_AREA_RATIO;
+ safeHeight *= SAFE_AREA_RATIO;
+ int left = (viewPortWidth - safeWidth) / 2;
+ int top = (viewPortHeight - safeHeight) / 2;
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].layout(
+ left,
+ top + safeHeight * i / MAX_ROWS,
+ left + safeWidth,
+ top + safeHeight * (i + 1) / MAX_ROWS);
+ }
+ }
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java b/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java
new file mode 100644
index 0000000..af36d7f
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media.subtitle;
+
+// Note: This is just copied from android.media.MediaTimeProvider.
+public interface MediaTimeProvider {
+ // we do not allow negative media time
+ /**
+ * Presentation time value if no timed event notification is requested.
+ */
+ public final static long NO_TIME = -1;
+
+ /**
+ * Cancels all previous notification request from this listener if any. It
+ * registers the listener to get seek and stop notifications. If timeUs is
+ * not negative, it also registers the listener for a timed event
+ * notification when the presentation time reaches (becomes greater) than
+ * the value specified. This happens immediately if the current media time
+ * is larger than or equal to timeUs.
+ *
+ * @param timeUs presentation time to get timed event callback at (or
+ * {@link #NO_TIME})
+ */
+ public void notifyAt(long timeUs, OnMediaTimeListener listener);
+
+ /**
+ * Cancels all previous notification request from this listener if any. It
+ * registers the listener to get seek and stop notifications. If the media
+ * is stopped, the listener will immediately receive a stop notification.
+ * Otherwise, it will receive a timed event notificaton.
+ */
+ public void scheduleUpdate(OnMediaTimeListener listener);
+
+ /**
+ * Cancels all previous notification request from this listener if any.
+ */
+ public void cancelNotifications(OnMediaTimeListener listener);
+
+ /**
+ * Get the current presentation time.
+ *
+ * @param precise Whether getting a precise time is important. This is
+ * more costly.
+ * @param monotonic Whether returned time should be monotonic: that is,
+ * greater than or equal to the last returned time. Don't
+ * always set this to true. E.g. this has undesired
+ * consequences if the media is seeked between calls.
+ * @throws IllegalStateException if the media is not initialized
+ */
+ public long getCurrentTimeUs(boolean precise, boolean monotonic)
+ throws IllegalStateException;
+
+ public static interface OnMediaTimeListener {
+ /**
+ * Called when the registered time was reached naturally.
+ *
+ * @param timeUs current media time
+ */
+ void onTimedEvent(long timeUs);
+
+ /**
+ * Called when the media time changed due to seeking.
+ *
+ * @param timeUs current media time
+ */
+ void onSeek(long timeUs);
+
+ /**
+ * Called when the playback stopped. This is not called on pause, only
+ * on full stop, at which point there is no further current media time.
+ */
+ void onStop();
+ }
+}
+
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
new file mode 100644
index 0000000..a4d55d7
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media.subtitle;
+
+import java.util.Locale;
+import java.util.Vector;
+
+import android.content.Context;
+import android.media.MediaFormat;
+import android.media.MediaPlayer2;
+import android.media.MediaPlayer2.TrackInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.accessibility.CaptioningManager;
+
+import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
+
+// Note: This is forked from android.media.SubtitleController since P
+/**
+ * The subtitle controller provides the architecture to display subtitles for a
+ * media source. It allows specifying which tracks to display, on which anchor
+ * to display them, and also allows adding external, out-of-band subtitle tracks.
+ */
+public class SubtitleController {
+ private MediaTimeProvider mTimeProvider;
+ private Vector<Renderer> mRenderers;
+ private Vector<SubtitleTrack> mTracks;
+ private SubtitleTrack mSelectedTrack;
+ private boolean mShowing;
+ private CaptioningManager mCaptioningManager;
+ private Handler mHandler;
+
+ private static final int WHAT_SHOW = 1;
+ private static final int WHAT_HIDE = 2;
+ private static final int WHAT_SELECT_TRACK = 3;
+ private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
+
+ private final Handler.Callback mCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case WHAT_SHOW:
+ doShow();
+ return true;
+ case WHAT_HIDE:
+ doHide();
+ return true;
+ case WHAT_SELECT_TRACK:
+ doSelectTrack((SubtitleTrack)msg.obj);
+ return true;
+ case WHAT_SELECT_DEFAULT_TRACK:
+ doSelectDefaultTrack();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+ new CaptioningManager.CaptioningChangeListener() {
+ @Override
+ public void onEnabledChanged(boolean enabled) {
+ selectDefaultTrack();
+ }
+
+ @Override
+ public void onLocaleChanged(Locale locale) {
+ selectDefaultTrack();
+ }
+ };
+
+ public SubtitleController(Context context) {
+ this(context, null, null);
+ }
+
+ /**
+ * Creates a subtitle controller for a media playback object that implements
+ * the MediaTimeProvider interface.
+ *
+ * @param timeProvider
+ */
+ public SubtitleController(
+ Context context,
+ MediaTimeProvider timeProvider,
+ Listener listener) {
+ mTimeProvider = timeProvider;
+ mListener = listener;
+
+ mRenderers = new Vector<Renderer>();
+ mShowing = false;
+ mTracks = new Vector<SubtitleTrack>();
+ mCaptioningManager =
+ (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
+ super.finalize();
+ }
+
+ /**
+ * @return the available subtitle tracks for this media. These include
+ * the tracks found by {@link MediaPlayer} as well as any tracks added
+ * manually via {@link #addTrack}.
+ */
+ public SubtitleTrack[] getTracks() {
+ synchronized(mTracks) {
+ SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+ mTracks.toArray(tracks);
+ return tracks;
+ }
+ }
+
+ /**
+ * @return the currently selected subtitle track
+ */
+ public SubtitleTrack getSelectedTrack() {
+ return mSelectedTrack;
+ }
+
+ private RenderingWidget getRenderingWidget() {
+ if (mSelectedTrack == null) {
+ return null;
+ }
+ return mSelectedTrack.getRenderingWidget();
+ }
+
+ /**
+ * Selects a subtitle track. As a result, this track will receive
+ * in-band data from the {@link MediaPlayer}. However, this does
+ * not change the subtitle visibility.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ *
+ * @param track The subtitle track to select. This must be one of the
+ * tracks in {@link #getTracks}.
+ * @return true if the track was successfully selected.
+ */
+ public boolean selectTrack(SubtitleTrack track) {
+ if (track != null && !mTracks.contains(track)) {
+ return false;
+ }
+
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
+ return true;
+ }
+
+ private void doSelectTrack(SubtitleTrack track) {
+ mTrackIsExplicit = true;
+ if (mSelectedTrack == track) {
+ return;
+ }
+
+ if (mSelectedTrack != null) {
+ mSelectedTrack.hide();
+ mSelectedTrack.setTimeProvider(null);
+ }
+
+ mSelectedTrack = track;
+ if (mAnchor != null) {
+ mAnchor.setSubtitleWidget(getRenderingWidget());
+ }
+
+ if (mSelectedTrack != null) {
+ mSelectedTrack.setTimeProvider(mTimeProvider);
+ mSelectedTrack.show();
+ }
+
+ if (mListener != null) {
+ mListener.onSubtitleTrackSelected(track);
+ }
+ }
+
+ /**
+ * @return the default subtitle track based on system preferences, or null,
+ * if no such track exists in this manager.
+ *
+ * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+ *
+ * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+ * consider all tracks, but prefer non-FORCED ones.
+ * 2. If user selected "Default" caption language:
+ * a. If there is a considered track with DEFAULT=yes, returns that track
+ * (favor the first one in the current language if there are more than
+ * one default tracks, or the first in general if none of them are in
+ * the current language).
+ * b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+ * language, return that one.
+ * c. If there are no default tracks, and no autoselectable tracks in the
+ * current language, return null.
+ * 3. If there is a track with the caption language, select that one. Prefer
+ * the one with AUTOSELECT=no.
+ *
+ * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+ * and FORCED=no.
+ */
+ public SubtitleTrack getDefaultTrack() {
+ SubtitleTrack bestTrack = null;
+ int bestScore = -1;
+
+ Locale selectedLocale = mCaptioningManager.getLocale();
+ Locale locale = selectedLocale;
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ boolean selectForced = !mCaptioningManager.isEnabled();
+
+ synchronized(mTracks) {
+ for (SubtitleTrack track: mTracks) {
+ MediaFormat format = track.getFormat();
+ String language = format.getString(MediaFormat.KEY_LANGUAGE);
+ boolean forced =
+ format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+ boolean autoselect =
+ format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+ boolean is_default =
+ format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+ boolean languageMatches =
+ (locale == null ||
+ locale.getLanguage().equals("") ||
+ locale.getISO3Language().equals(language) ||
+ locale.getLanguage().equals(language));
+ // is_default is meaningless unless caption language is 'default'
+ int score = (forced ? 0 : 8) +
+ (((selectedLocale == null) && is_default) ? 4 : 0) +
+ (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+ if (selectForced && !forced) {
+ continue;
+ }
+
+ // we treat null locale/language as matching any language
+ if ((selectedLocale == null && is_default) ||
+ (languageMatches &&
+ (autoselect || forced || selectedLocale != null))) {
+ if (score > bestScore) {
+ bestScore = score;
+ bestTrack = track;
+ }
+ }
+ }
+ }
+ return bestTrack;
+ }
+
+ private boolean mTrackIsExplicit = false;
+ private boolean mVisibilityIsExplicit = false;
+
+ /** should be called from anchor thread */
+ public void selectDefaultTrack() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
+ }
+
+ private void doSelectDefaultTrack() {
+ if (mTrackIsExplicit) {
+ // If track selection is explicit, but visibility
+ // is not, it falls back to the captioning setting
+ if (!mVisibilityIsExplicit) {
+ if (mCaptioningManager.isEnabled() ||
+ (mSelectedTrack != null &&
+ mSelectedTrack.getFormat().getInteger(
+ MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
+ show();
+ } else if (mSelectedTrack != null
+ && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ hide();
+ }
+ mVisibilityIsExplicit = false;
+ }
+ return;
+ }
+
+ // We can have a default (forced) track even if captioning
+ // is not enabled. This is handled by getDefaultTrack().
+ // Show this track unless subtitles were explicitly hidden.
+ SubtitleTrack track = getDefaultTrack();
+ if (track != null) {
+ selectTrack(track);
+ mTrackIsExplicit = false;
+ if (!mVisibilityIsExplicit) {
+ show();
+ mVisibilityIsExplicit = false;
+ }
+ }
+ }
+
+ /** must be called from anchor thread */
+ public void reset() {
+ checkAnchorLooper();
+ hide();
+ selectTrack(null);
+ mTracks.clear();
+ mTrackIsExplicit = false;
+ mVisibilityIsExplicit = false;
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
+ }
+
+ /**
+ * Adds a new, external subtitle track to the manager.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ * @return the created {@link SubtitleTrack} object
+ */
+ public SubtitleTrack addTrack(MediaFormat format) {
+ synchronized(mRenderers) {
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ SubtitleTrack track = renderer.createTrack(format);
+ if (track != null) {
+ synchronized(mTracks) {
+ if (mTracks.size() == 0) {
+ mCaptioningManager.addCaptioningChangeListener(
+ mCaptioningChangeListener);
+ }
+ mTracks.add(track);
+ }
+ return track;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Show the selected (or default) subtitle track.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ */
+ public void show() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
+ }
+
+ private void doShow() {
+ mShowing = true;
+ mVisibilityIsExplicit = true;
+ if (mSelectedTrack != null) {
+ mSelectedTrack.show();
+ }
+ }
+
+ /**
+ * Hide the selected (or default) subtitle track.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ */
+ public void hide() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
+ }
+
+ private void doHide() {
+ mVisibilityIsExplicit = true;
+ if (mSelectedTrack != null) {
+ mSelectedTrack.hide();
+ }
+ mShowing = false;
+ }
+
+ /**
+ * Interface for supporting a single or multiple subtitle types in {@link
+ * MediaPlayer}.
+ */
+ public abstract static class Renderer {
+ /**
+ * Called by {@link MediaPlayer}'s {@link SubtitleController} when a new
+ * subtitle track is detected, to see if it should use this object to
+ * parse and display this subtitle track.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ *
+ * @return true if and only if the track format is supported by this
+ * renderer
+ */
+ public abstract boolean supports(MediaFormat format);
+
+ /**
+ * Called by {@link MediaPlayer}'s {@link SubtitleController} for each
+ * subtitle track that was detected and is supported by this object to
+ * create a {@link SubtitleTrack} object. This object will be created
+ * for each track that was found. If the track is selected for display,
+ * this object will be used to parse and display the track data.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ * @return a {@link SubtitleTrack} object that will be used to parse
+ * and render the subtitle track.
+ */
+ public abstract SubtitleTrack createTrack(MediaFormat format);
+ }
+
+ /**
+ * Add support for a subtitle format in {@link MediaPlayer}.
+ *
+ * @param renderer a {@link SubtitleController.Renderer} object that adds
+ * support for a subtitle format.
+ */
+ public void registerRenderer(Renderer renderer) {
+ synchronized(mRenderers) {
+ // TODO how to get available renderers in the system
+ if (!mRenderers.contains(renderer)) {
+ // TODO should added renderers override existing ones (to allow replacing?)
+ mRenderers.add(renderer);
+ }
+ }
+ }
+
+ public boolean hasRendererFor(MediaFormat format) {
+ synchronized(mRenderers) {
+ // TODO how to get available renderers in the system
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Subtitle anchor, an object that is able to display a subtitle renderer,
+ * e.g. a VideoView.
+ */
+ public interface Anchor {
+ /**
+ * Anchor should use the supplied subtitle rendering widget, or
+ * none if it is null.
+ */
+ public void setSubtitleWidget(RenderingWidget subtitleWidget);
+
+ /**
+ * Anchors provide the looper on which all track visibility changes
+ * (track.show/hide, setSubtitleWidget) will take place.
+ */
+ public Looper getSubtitleLooper();
+ }
+
+ private Anchor mAnchor;
+
+ /**
+ * called from anchor's looper (if any, both when unsetting and
+ * setting)
+ */
+ public void setAnchor(Anchor anchor) {
+ if (mAnchor == anchor) {
+ return;
+ }
+
+ if (mAnchor != null) {
+ checkAnchorLooper();
+ mAnchor.setSubtitleWidget(null);
+ }
+ mAnchor = anchor;
+ mHandler = null;
+ if (mAnchor != null) {
+ mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
+ checkAnchorLooper();
+ mAnchor.setSubtitleWidget(getRenderingWidget());
+ }
+ }
+
+ private void checkAnchorLooper() {
+ assert mHandler != null : "Should have a looper already";
+ assert Looper.myLooper() == mHandler.getLooper()
+ : "Must be called from the anchor's looper";
+ }
+
+ private void processOnAnchor(Message m) {
+ assert mHandler != null : "Should have a looper already";
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ mHandler.dispatchMessage(m);
+ } else {
+ mHandler.sendMessage(m);
+ }
+ }
+
+ public interface Listener {
+ /**
+ * Called when a subtitle track has been selected.
+ *
+ * @param track selected subtitle track or null
+ */
+ public void onSubtitleTrackSelected(SubtitleTrack track);
+ }
+
+ private Listener mListener;
+}
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java
new file mode 100644
index 0000000..6b9064a
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java
@@ -0,0 +1,696 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media.subtitle;
+
+import android.graphics.Canvas;
+import android.media.MediaFormat;
+import android.media.MediaPlayer2.TrackInfo;
+import android.media.SubtitleData;
+import android.os.Handler;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Pair;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Vector;
+
+// Note: This is forked from android.media.SubtitleTrack since P
+/**
+ * A subtitle track abstract base class that is responsible for parsing and displaying
+ * an instance of a particular type of subtitle.
+ */
+public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeListener {
+ private static final String TAG = "SubtitleTrack";
+ private long mLastUpdateTimeMs;
+ private long mLastTimeMs;
+
+ private Runnable mRunnable;
+
+ final private LongSparseArray<Run> mRunsByEndTime = new LongSparseArray<Run>();
+ final private LongSparseArray<Run> mRunsByID = new LongSparseArray<Run>();
+
+ private CueList mCues;
+ final private Vector<Cue> mActiveCues = new Vector<Cue>();
+ protected boolean mVisible;
+
+ public boolean DEBUG = false;
+
+ protected Handler mHandler = new Handler();
+
+ private MediaFormat mFormat;
+
+ public SubtitleTrack(MediaFormat format) {
+ mFormat = format;
+ mCues = new CueList();
+ clearActiveCues();
+ mLastTimeMs = -1;
+ }
+
+ public final MediaFormat getFormat() {
+ return mFormat;
+ }
+
+ private long mNextScheduledTimeMs = -1;
+
+ public void onData(SubtitleData data) {
+ long runID = data.getStartTimeUs() + 1;
+ onData(data.getData(), true /* eos */, runID);
+ setRunDiscardTimeMs(
+ runID,
+ (data.getStartTimeUs() + data.getDurationUs()) / 1000);
+ }
+
+ /**
+ * Called when there is input data for the subtitle track. The
+ * complete subtitle for a track can include multiple whole units
+ * (runs). Each of these units can have multiple sections. The
+ * contents of a run are submitted in sequential order, with eos
+ * indicating the last section of the run. Calls from different
+ * runs must not be intermixed.
+ *
+ * @param data subtitle data byte buffer
+ * @param eos true if this is the last section of the run.
+ * @param runID mostly-unique ID for this run of data. Subtitle cues
+ * with runID of 0 are discarded immediately after
+ * display. Cues with runID of ~0 are discarded
+ * only at the deletion of the track object. Cues
+ * with other runID-s are discarded at the end of the
+ * run, which defaults to the latest timestamp of
+ * any of its cues (with this runID).
+ */
+ protected abstract void onData(byte[] data, boolean eos, long runID);
+
+ /**
+ * Called when adding the subtitle rendering widget to the view hierarchy,
+ * as well as when showing or hiding the subtitle track, or when the video
+ * surface position has changed.
+ *
+ * @return the widget that renders this subtitle track. For most renderers
+ * there should be a single shared instance that is used for all
+ * tracks supported by that renderer, as at most one subtitle track
+ * is visible at one time.
+ */
+ public abstract RenderingWidget getRenderingWidget();
+
+ /**
+ * Called when the active cues have changed, and the contents of the subtitle
+ * view should be updated.
+ */
+ public abstract void updateView(Vector<Cue> activeCues);
+
+ protected synchronized void updateActiveCues(boolean rebuild, long timeMs) {
+ // out-of-order times mean seeking or new active cues being added
+ // (during their own timespan)
+ if (rebuild || mLastUpdateTimeMs > timeMs) {
+ clearActiveCues();
+ }
+
+ for(Iterator<Pair<Long, Cue> > it =
+ mCues.entriesBetween(mLastUpdateTimeMs, timeMs).iterator(); it.hasNext(); ) {
+ Pair<Long, Cue> event = it.next();
+ Cue cue = event.second;
+
+ if (cue.mEndTimeMs == event.first) {
+ // remove past cues
+ if (DEBUG) Log.v(TAG, "Removing " + cue);
+ mActiveCues.remove(cue);
+ if (cue.mRunID == 0) {
+ it.remove();
+ }
+ } else if (cue.mStartTimeMs == event.first) {
+ // add new cues
+ // TRICKY: this will happen in start order
+ if (DEBUG) Log.v(TAG, "Adding " + cue);
+ if (cue.mInnerTimesMs != null) {
+ cue.onTime(timeMs);
+ }
+ mActiveCues.add(cue);
+ } else if (cue.mInnerTimesMs != null) {
+ // cue is modified
+ cue.onTime(timeMs);
+ }
+ }
+
+ /* complete any runs */
+ while (mRunsByEndTime.size() > 0 &&
+ mRunsByEndTime.keyAt(0) <= timeMs) {
+ removeRunsByEndTimeIndex(0); // removes element
+ }
+ mLastUpdateTimeMs = timeMs;
+ }
+
+ private void removeRunsByEndTimeIndex(int ix) {
+ Run run = mRunsByEndTime.valueAt(ix);
+ while (run != null) {
+ Cue cue = run.mFirstCue;
+ while (cue != null) {
+ mCues.remove(cue);
+ Cue nextCue = cue.mNextInRun;
+ cue.mNextInRun = null;
+ cue = nextCue;
+ }
+ mRunsByID.remove(run.mRunID);
+ Run nextRun = run.mNextRunAtEndTimeMs;
+ run.mPrevRunAtEndTimeMs = null;
+ run.mNextRunAtEndTimeMs = null;
+ run = nextRun;
+ }
+ mRunsByEndTime.removeAt(ix);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ /* remove all cues (untangle all cross-links) */
+ int size = mRunsByEndTime.size();
+ for(int ix = size - 1; ix >= 0; ix--) {
+ removeRunsByEndTimeIndex(ix);
+ }
+
+ super.finalize();
+ }
+
+ private synchronized void takeTime(long timeMs) {
+ mLastTimeMs = timeMs;
+ }
+
+ protected synchronized void clearActiveCues() {
+ if (DEBUG) Log.v(TAG, "Clearing " + mActiveCues.size() + " active cues");
+ mActiveCues.clear();
+ mLastUpdateTimeMs = -1;
+ }
+
+ protected void scheduleTimedEvents() {
+ /* get times for the next event */
+ if (mTimeProvider != null) {
+ mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
+ if (DEBUG) Log.d(TAG, "sched @" + mNextScheduledTimeMs + " after " + mLastTimeMs);
+ mTimeProvider.notifyAt(
+ mNextScheduledTimeMs >= 0 ?
+ (mNextScheduledTimeMs * 1000) : MediaTimeProvider.NO_TIME,
+ this);
+ }
+ }
+
+ @Override
+ public void onTimedEvent(long timeUs) {
+ if (DEBUG) Log.d(TAG, "onTimedEvent " + timeUs);
+ synchronized (this) {
+ long timeMs = timeUs / 1000;
+ updateActiveCues(false, timeMs);
+ takeTime(timeMs);
+ }
+ updateView(mActiveCues);
+ scheduleTimedEvents();
+ }
+
+ @Override
+ public void onSeek(long timeUs) {
+ if (DEBUG) Log.d(TAG, "onSeek " + timeUs);
+ synchronized (this) {
+ long timeMs = timeUs / 1000;
+ updateActiveCues(true, timeMs);
+ takeTime(timeMs);
+ }
+ updateView(mActiveCues);
+ scheduleTimedEvents();
+ }
+
+ @Override
+ public void onStop() {
+ synchronized (this) {
+ if (DEBUG) Log.d(TAG, "onStop");
+ clearActiveCues();
+ mLastTimeMs = -1;
+ }
+ updateView(mActiveCues);
+ mNextScheduledTimeMs = -1;
+ mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+ }
+
+ protected MediaTimeProvider mTimeProvider;
+
+ public void show() {
+ if (mVisible) {
+ return;
+ }
+
+ mVisible = true;
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(true);
+ }
+ if (mTimeProvider != null) {
+ mTimeProvider.scheduleUpdate(this);
+ }
+ }
+
+ public void hide() {
+ if (!mVisible) {
+ return;
+ }
+
+ if (mTimeProvider != null) {
+ mTimeProvider.cancelNotifications(this);
+ }
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(false);
+ }
+ mVisible = false;
+ }
+
+ protected synchronized boolean addCue(Cue cue) {
+ mCues.add(cue);
+
+ if (cue.mRunID != 0) {
+ Run run = mRunsByID.get(cue.mRunID);
+ if (run == null) {
+ run = new Run();
+ mRunsByID.put(cue.mRunID, run);
+ run.mEndTimeMs = cue.mEndTimeMs;
+ } else if (run.mEndTimeMs < cue.mEndTimeMs) {
+ run.mEndTimeMs = cue.mEndTimeMs;
+ }
+
+ // link-up cues in the same run
+ cue.mNextInRun = run.mFirstCue;
+ run.mFirstCue = cue;
+ }
+
+ // if a cue is added that should be visible, need to refresh view
+ long nowMs = -1;
+ if (mTimeProvider != null) {
+ try {
+ nowMs = mTimeProvider.getCurrentTimeUs(
+ false /* precise */, true /* monotonic */) / 1000;
+ } catch (IllegalStateException e) {
+ // handle as it we are not playing
+ }
+ }
+
+ if (DEBUG) Log.v(TAG, "mVisible=" + mVisible + ", " +
+ cue.mStartTimeMs + " <= " + nowMs + ", " +
+ cue.mEndTimeMs + " >= " + mLastTimeMs);
+
+ if (mVisible &&
+ cue.mStartTimeMs <= nowMs &&
+ // we don't trust nowMs, so check any cue since last callback
+ cue.mEndTimeMs >= mLastTimeMs) {
+ if (mRunnable != null) {
+ mHandler.removeCallbacks(mRunnable);
+ }
+ final SubtitleTrack track = this;
+ final long thenMs = nowMs;
+ mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // even with synchronized, it is possible that we are going
+ // to do multiple updates as the runnable could be already
+ // running.
+ synchronized (track) {
+ mRunnable = null;
+ updateActiveCues(true, thenMs);
+ updateView(mActiveCues);
+ }
+ }
+ };
+ // delay update so we don't update view on every cue. TODO why 10?
+ if (mHandler.postDelayed(mRunnable, 10 /* delay */)) {
+ if (DEBUG) Log.v(TAG, "scheduling update");
+ } else {
+ if (DEBUG) Log.w(TAG, "failed to schedule subtitle view update");
+ }
+ return true;
+ }
+
+ if (mVisible &&
+ cue.mEndTimeMs >= mLastTimeMs &&
+ (cue.mStartTimeMs < mNextScheduledTimeMs ||
+ mNextScheduledTimeMs < 0)) {
+ scheduleTimedEvents();
+ }
+
+ return false;
+ }
+
+ public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
+ if (mTimeProvider == timeProvider) {
+ return;
+ }
+ if (mTimeProvider != null) {
+ mTimeProvider.cancelNotifications(this);
+ }
+ mTimeProvider = timeProvider;
+ if (mTimeProvider != null) {
+ mTimeProvider.scheduleUpdate(this);
+ }
+ }
+
+
+ static class CueList {
+ private static final String TAG = "CueList";
+ // simplistic, inefficient implementation
+ private SortedMap<Long, Vector<Cue> > mCues;
+ public boolean DEBUG = false;
+
+ private boolean addEvent(Cue cue, long timeMs) {
+ Vector<Cue> cues = mCues.get(timeMs);
+ if (cues == null) {
+ cues = new Vector<Cue>(2);
+ mCues.put(timeMs, cues);
+ } else if (cues.contains(cue)) {
+ // do not duplicate cues
+ return false;
+ }
+
+ cues.add(cue);
+ return true;
+ }
+
+ private void removeEvent(Cue cue, long timeMs) {
+ Vector<Cue> cues = mCues.get(timeMs);
+ if (cues != null) {
+ cues.remove(cue);
+ if (cues.size() == 0) {
+ mCues.remove(timeMs);
+ }
+ }
+ }
+
+ public void add(Cue cue) {
+ // ignore non-positive-duration cues
+ if (cue.mStartTimeMs >= cue.mEndTimeMs)
+ return;
+
+ if (!addEvent(cue, cue.mStartTimeMs)) {
+ return;
+ }
+
+ long lastTimeMs = cue.mStartTimeMs;
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ if (timeMs > lastTimeMs && timeMs < cue.mEndTimeMs) {
+ addEvent(cue, timeMs);
+ lastTimeMs = timeMs;
+ }
+ }
+ }
+
+ addEvent(cue, cue.mEndTimeMs);
+ }
+
+ public void remove(Cue cue) {
+ removeEvent(cue, cue.mStartTimeMs);
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ removeEvent(cue, timeMs);
+ }
+ }
+ removeEvent(cue, cue.mEndTimeMs);
+ }
+
+ public Iterable<Pair<Long, Cue>> entriesBetween(
+ final long lastTimeMs, final long timeMs) {
+ return new Iterable<Pair<Long, Cue> >() {
+ @Override
+ public Iterator<Pair<Long, Cue> > iterator() {
+ if (DEBUG) Log.d(TAG, "slice (" + lastTimeMs + ", " + timeMs + "]=");
+ try {
+ return new EntryIterator(
+ mCues.subMap(lastTimeMs + 1, timeMs + 1));
+ } catch(IllegalArgumentException e) {
+ return new EntryIterator(null);
+ }
+ }
+ };
+ }
+
+ public long nextTimeAfter(long timeMs) {
+ SortedMap<Long, Vector<Cue>> tail = null;
+ try {
+ tail = mCues.tailMap(timeMs + 1);
+ if (tail != null) {
+ return tail.firstKey();
+ } else {
+ return -1;
+ }
+ } catch(IllegalArgumentException e) {
+ return -1;
+ } catch(NoSuchElementException e) {
+ return -1;
+ }
+ }
+
+ class EntryIterator implements Iterator<Pair<Long, Cue> > {
+ @Override
+ public boolean hasNext() {
+ return !mDone;
+ }
+
+ @Override
+ public Pair<Long, Cue> next() {
+ if (mDone) {
+ throw new NoSuchElementException("");
+ }
+ mLastEntry = new Pair<Long, Cue>(
+ mCurrentTimeMs, mListIterator.next());
+ mLastListIterator = mListIterator;
+ if (!mListIterator.hasNext()) {
+ nextKey();
+ }
+ return mLastEntry;
+ }
+
+ @Override
+ public void remove() {
+ // only allow removing end tags
+ if (mLastListIterator == null ||
+ mLastEntry.second.mEndTimeMs != mLastEntry.first) {
+ throw new IllegalStateException("");
+ }
+
+ // remove end-cue
+ mLastListIterator.remove();
+ mLastListIterator = null;
+ if (mCues.get(mLastEntry.first).size() == 0) {
+ mCues.remove(mLastEntry.first);
+ }
+
+ // remove rest of the cues
+ Cue cue = mLastEntry.second;
+ removeEvent(cue, cue.mStartTimeMs);
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ removeEvent(cue, timeMs);
+ }
+ }
+ }
+
+ public EntryIterator(SortedMap<Long, Vector<Cue> > cues) {
+ if (DEBUG) Log.v(TAG, cues + "");
+ mRemainingCues = cues;
+ mLastListIterator = null;
+ nextKey();
+ }
+
+ private void nextKey() {
+ do {
+ try {
+ if (mRemainingCues == null) {
+ throw new NoSuchElementException("");
+ }
+ mCurrentTimeMs = mRemainingCues.firstKey();
+ mListIterator =
+ mRemainingCues.get(mCurrentTimeMs).iterator();
+ try {
+ mRemainingCues =
+ mRemainingCues.tailMap(mCurrentTimeMs + 1);
+ } catch (IllegalArgumentException e) {
+ mRemainingCues = null;
+ }
+ mDone = false;
+ } catch (NoSuchElementException e) {
+ mDone = true;
+ mRemainingCues = null;
+ mListIterator = null;
+ return;
+ }
+ } while (!mListIterator.hasNext());
+ }
+
+ private long mCurrentTimeMs;
+ private Iterator<Cue> mListIterator;
+ private boolean mDone;
+ private SortedMap<Long, Vector<Cue> > mRemainingCues;
+ private Iterator<Cue> mLastListIterator;
+ private Pair<Long,Cue> mLastEntry;
+ }
+
+ CueList() {
+ mCues = new TreeMap<Long, Vector<Cue>>();
+ }
+ }
+
+ public static class Cue {
+ public long mStartTimeMs;
+ public long mEndTimeMs;
+ public long[] mInnerTimesMs;
+ public long mRunID;
+
+ public Cue mNextInRun;
+
+ public void onTime(long timeMs) { }
+ }
+
+ /** update mRunsByEndTime (with default end time) */
+ protected void finishedRun(long runID) {
+ if (runID != 0 && runID != ~0) {
+ Run run = mRunsByID.get(runID);
+ if (run != null) {
+ run.storeByEndTimeMs(mRunsByEndTime);
+ }
+ }
+ }
+
+ /** update mRunsByEndTime with given end time */
+ public void setRunDiscardTimeMs(long runID, long timeMs) {
+ if (runID != 0 && runID != ~0) {
+ Run run = mRunsByID.get(runID);
+ if (run != null) {
+ run.mEndTimeMs = timeMs;
+ run.storeByEndTimeMs(mRunsByEndTime);
+ }
+ }
+ }
+
+ /** whether this is a text track who fires events instead getting rendered */
+ public int getTrackType() {
+ return getRenderingWidget() == null
+ ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
+ : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
+ }
+
+
+ private static class Run {
+ public Cue mFirstCue;
+ public Run mNextRunAtEndTimeMs;
+ public Run mPrevRunAtEndTimeMs;
+ public long mEndTimeMs = -1;
+ public long mRunID = 0;
+ private long mStoredEndTimeMs = -1;
+
+ public void storeByEndTimeMs(LongSparseArray<Run> runsByEndTime) {
+ // remove old value if any
+ int ix = runsByEndTime.indexOfKey(mStoredEndTimeMs);
+ if (ix >= 0) {
+ if (mPrevRunAtEndTimeMs == null) {
+ assert(this == runsByEndTime.valueAt(ix));
+ if (mNextRunAtEndTimeMs == null) {
+ runsByEndTime.removeAt(ix);
+ } else {
+ runsByEndTime.setValueAt(ix, mNextRunAtEndTimeMs);
+ }
+ }
+ removeAtEndTimeMs();
+ }
+
+ // add new value
+ if (mEndTimeMs >= 0) {
+ mPrevRunAtEndTimeMs = null;
+ mNextRunAtEndTimeMs = runsByEndTime.get(mEndTimeMs);
+ if (mNextRunAtEndTimeMs != null) {
+ mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = this;
+ }
+ runsByEndTime.put(mEndTimeMs, this);
+ mStoredEndTimeMs = mEndTimeMs;
+ }
+ }
+
+ public void removeAtEndTimeMs() {
+ Run prev = mPrevRunAtEndTimeMs;
+
+ if (mPrevRunAtEndTimeMs != null) {
+ mPrevRunAtEndTimeMs.mNextRunAtEndTimeMs = mNextRunAtEndTimeMs;
+ mPrevRunAtEndTimeMs = null;
+ }
+ if (mNextRunAtEndTimeMs != null) {
+ mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = prev;
+ mNextRunAtEndTimeMs = null;
+ }
+ }
+ }
+
+ /**
+ * Interface for rendering subtitles onto a Canvas.
+ */
+ public interface RenderingWidget {
+ /**
+ * Sets the widget's callback, which is used to send updates when the
+ * rendered data has changed.
+ *
+ * @param callback update callback
+ */
+ public void setOnChangedListener(OnChangedListener callback);
+
+ /**
+ * Sets the widget's size.
+ *
+ * @param width width in pixels
+ * @param height height in pixels
+ */
+ public void setSize(int width, int height);
+
+ /**
+ * Sets whether the widget should draw subtitles.
+ *
+ * @param visible true if subtitles should be drawn, false otherwise
+ */
+ public void setVisible(boolean visible);
+
+ /**
+ * Renders subtitles onto a {@link Canvas}.
+ *
+ * @param c canvas on which to render subtitles
+ */
+ public void draw(Canvas c);
+
+ /**
+ * Called when the widget is attached to a window.
+ */
+ public void onAttachedToWindow();
+
+ /**
+ * Called when the widget is detached from a window.
+ */
+ public void onDetachedFromWindow();
+
+ /**
+ * Callback used to send updates about changes to rendering data.
+ */
+ public interface OnChangedListener {
+ /**
+ * Called when the rendering data has changed.
+ *
+ * @param renderingWidget the widget whose data has changed
+ */
+ public void onChanged(RenderingWidget renderingWidget);
+ }
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 07b8788..d7be549 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -18,9 +18,7 @@
import android.app.Notification;
import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
-import android.media.DataSourceDesc;
+import android.content.pm.ApplicationInfo;
import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
import android.media.MediaController2;
@@ -31,17 +29,14 @@
import android.media.MediaLibraryService2.MediaLibrarySession;
import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import android.media.MediaMetadata2;
-import android.media.MediaPlayerBase;
import android.media.MediaPlaylistAgent;
import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.PlaylistParams;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.MediaSessionService2.MediaNotification;
-import android.media.PlaybackState2;
import android.media.Rating2;
import android.media.SessionToken2;
import android.media.VolumeProvider2;
@@ -55,10 +50,8 @@
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSession2Provider.BuilderBaseProvider;
import android.media.update.MediaSession2Provider.CommandButtonProvider.BuilderProvider;
-import android.media.update.MediaSession2Provider.PlaylistParamsProvider;
import android.media.update.MediaSessionService2Provider;
import android.media.update.MediaSessionService2Provider.MediaNotificationProvider;
-import android.media.update.PlaybackState2Provider;
import android.media.update.SessionToken2Provider;
import android.media.update.StaticProvider;
import android.media.update.VideoView2Provider;
@@ -71,7 +64,7 @@
import android.widget.MediaControlView2;
import android.widget.VideoView2;
-import com.android.media.IMediaSession2Callback;
+import com.android.media.IMediaController2;
import com.android.media.MediaBrowser2Impl;
import com.android.media.MediaController2Impl;
import com.android.media.MediaItem2Impl;
@@ -80,9 +73,7 @@
import com.android.media.MediaMetadata2Impl;
import com.android.media.MediaPlaylistAgentImpl;
import com.android.media.MediaSession2Impl;
-import com.android.media.MediaSession2Impl.PlaylistParamsImpl;
import com.android.media.MediaSessionService2Impl;
-import com.android.media.PlaybackState2Impl;
import com.android.media.Rating2Impl;
import com.android.media.SessionToken2Impl;
import com.android.media.VolumeProvider2Impl;
@@ -91,10 +82,11 @@
import java.util.concurrent.Executor;
-public class ApiFactory implements StaticProvider {
- public static Object initialize(Resources libResources, Theme libTheme)
- throws ReflectiveOperationException {
- ApiHelper.initialize(libResources, libTheme);
+public final class ApiFactory implements StaticProvider {
+ private ApiFactory() { }
+
+ public static StaticProvider initialize(ApplicationInfo updatableInfo) {
+ ApiHelper.initialize(updatableInfo);
return new ApiFactory();
}
@@ -113,7 +105,7 @@
@Override
public MediaSession2Provider.CommandProvider createMediaSession2Command(
- Command instance, int commandCode, String action, Bundle extra) {
+ SessionCommand2 instance, int commandCode, String action, Bundle extra) {
if (action == null && extra == null) {
return new MediaSession2Impl.CommandImpl(instance, commandCode);
}
@@ -121,20 +113,20 @@
}
@Override
- public Command fromBundle_MediaSession2Command(Context context, Bundle command) {
- return MediaSession2Impl.CommandImpl.fromBundle_impl(context, command);
+ public SessionCommand2 fromBundle_MediaSession2Command(Bundle command) {
+ return MediaSession2Impl.CommandImpl.fromBundle_impl(command);
}
@Override
public MediaSession2Provider.CommandGroupProvider createMediaSession2CommandGroup(
- Context context, CommandGroup instance, CommandGroup other) {
- return new MediaSession2Impl.CommandGroupImpl(context, instance,
+ SessionCommandGroup2 instance, SessionCommandGroup2 other) {
+ return new MediaSession2Impl.CommandGroupImpl(instance,
(other == null) ? null : other.getProvider());
}
@Override
- public CommandGroup fromBundle_MediaSession2CommandGroup(Context context, Bundle commands) {
- return MediaSession2Impl.CommandGroupImpl.fromBundle_impl(context, commands);
+ public SessionCommandGroup2 fromBundle_MediaSession2CommandGroup(Bundle commands) {
+ return MediaSession2Impl.CommandGroupImpl.fromBundle_impl(commands);
}
@Override
@@ -142,26 +134,13 @@
Context context, ControllerInfo instance, int uid, int pid, String packageName,
IInterface callback) {
return new MediaSession2Impl.ControllerInfoImpl(context,
- instance, uid, pid, packageName, (IMediaSession2Callback) callback);
+ instance, uid, pid, packageName, (IMediaController2) callback);
}
@Override
- public PlaylistParamsProvider createMediaSession2PlaylistParams(Context context,
- PlaylistParams playlistParams, int repeatMode, int shuffleMode,
- MediaMetadata2 playlistMetadata) {
- return new PlaylistParamsImpl(context, playlistParams, repeatMode, shuffleMode,
- playlistMetadata);
- }
-
- @Override
- public PlaylistParams fromBundle_PlaylistParams(Context context, Bundle bundle) {
- return PlaylistParamsImpl.fromBundle(context, bundle);
- }
-
- @Override
- public BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
+ public BuilderProvider createMediaSession2CommandButtonBuilder(
MediaSession2.CommandButton.Builder instance) {
- return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(context, instance);
+ return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(instance);
}
public BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
@@ -170,21 +149,19 @@
}
@Override
- public MediaSessionService2Provider createMediaSessionService2(
- MediaSessionService2 instance) {
+ public MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance) {
return new MediaSessionService2Impl(instance);
}
@Override
- public MediaNotificationProvider createMediaSessionService2MediaNotification(Context context,
+ public MediaNotificationProvider createMediaSessionService2MediaNotification(
MediaNotification instance, int notificationId, Notification notification) {
return new MediaSessionService2Impl.MediaNotificationImpl(
- context, instance, notificationId, notification);
+ instance, notificationId, notification);
}
@Override
- public MediaSessionService2Provider createMediaLibraryService2(
- MediaLibraryService2 instance) {
+ public MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance) {
return new MediaLibraryService2Impl(instance);
}
@@ -198,9 +175,9 @@
}
@Override
- public LibraryRootProvider createMediaLibraryService2LibraryRoot(Context context,
+ public LibraryRootProvider createMediaLibraryService2LibraryRoot(
LibraryRoot instance, String rootId, Bundle extras) {
- return new LibraryRootImpl(context, instance, rootId, extras);
+ return new LibraryRootImpl(instance, rootId, extras);
}
@Override
@@ -224,90 +201,76 @@
}
@Override
- public SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle) {
- return SessionToken2Impl.fromBundle_impl(context, bundle);
+ public SessionToken2 fromBundle_SessionToken2(Bundle bundle) {
+ return SessionToken2Impl.fromBundle_impl(bundle);
}
@Override
- public MediaItem2Provider.BuilderProvider createMediaItem2Builder(
- Context context, MediaItem2.Builder instance, int flags) {
- return new MediaItem2Impl.BuilderImpl(context, instance, flags);
+ public MediaItem2Provider.BuilderProvider createMediaItem2Builder(MediaItem2.Builder instance,
+ int flags) {
+ return new MediaItem2Impl.BuilderImpl(instance, flags);
}
@Override
- public MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle) {
- return MediaItem2Impl.fromBundle(context, bundle);
+ public MediaItem2 fromBundle_MediaItem2(Bundle bundle) {
+ return MediaItem2Impl.fromBundle_impl(bundle);
}
@Override
- public VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
- int controlType, int maxVolume, int currentVolume) {
- return new VolumeProvider2Impl(context, instance, controlType, maxVolume, currentVolume);
+ public VolumeProvider2Provider createVolumeProvider2(VolumeProvider2 instance, int controlType,
+ int maxVolume, int currentVolume) {
+ return new VolumeProvider2Impl(instance, controlType, maxVolume, currentVolume);
}
@Override
- public MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle) {
- return MediaMetadata2Impl.fromBundle(context, bundle);
+ public MediaMetadata2 fromBundle_MediaMetadata2(Bundle bundle) {
+ return MediaMetadata2Impl.fromBundle_impl(bundle);
}
@Override
public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder instance) {
- return new MediaMetadata2Impl.BuilderImpl(context, instance);
+ MediaMetadata2.Builder instance) {
+ return new MediaMetadata2Impl.BuilderImpl(instance);
}
@Override
public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- Context context, MediaMetadata2.Builder instance, MediaMetadata2 source) {
- return new MediaMetadata2Impl.BuilderImpl(context, instance, source);
+ MediaMetadata2.Builder instance, MediaMetadata2 source) {
+ return new MediaMetadata2Impl.BuilderImpl(instance, source);
}
@Override
- public Rating2 fromBundle_Rating2(Context context, Bundle bundle) {
- return Rating2Impl.fromBundle(context, bundle);
+ public Rating2 fromBundle_Rating2(Bundle bundle) {
+ return Rating2Impl.fromBundle_impl(bundle);
}
@Override
- public Rating2 newUnratedRating_Rating2(Context context, int ratingStyle) {
- return Rating2Impl.newUnratedRating(context, ratingStyle);
+ public Rating2 newUnratedRating_Rating2(int ratingStyle) {
+ return Rating2Impl.newUnratedRating_impl(ratingStyle);
}
@Override
- public Rating2 newHeartRating_Rating2(Context context, boolean hasHeart) {
- return Rating2Impl.newHeartRating(context, hasHeart);
+ public Rating2 newHeartRating_Rating2(boolean hasHeart) {
+ return Rating2Impl.newHeartRating_impl(hasHeart);
}
@Override
- public Rating2 newThumbRating_Rating2(Context context, boolean thumbIsUp) {
- return Rating2Impl.newThumbRating(context, thumbIsUp);
+ public Rating2 newThumbRating_Rating2(boolean thumbIsUp) {
+ return Rating2Impl.newThumbRating_impl(thumbIsUp);
}
@Override
- public Rating2 newStarRating_Rating2(Context context, int starRatingStyle, float starRating) {
- return Rating2Impl.newStarRating(context, starRatingStyle, starRating);
+ public Rating2 newStarRating_Rating2(int starRatingStyle, float starRating) {
+ return Rating2Impl.newStarRating_impl(starRatingStyle, starRating);
}
@Override
- public Rating2 newPercentageRating_Rating2(Context context, float percent) {
- return Rating2Impl.newPercentageRating(context, percent);
+ public Rating2 newPercentageRating_Rating2(float percent) {
+ return Rating2Impl.newPercentageRating_impl(percent);
}
@Override
- public PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance,
- int state, long position, long updateTime, float speed, long bufferedPosition,
- long activeItemId) {
- return new PlaybackState2Impl(context, instance, state, position, updateTime, speed,
- bufferedPosition, activeItemId);
- }
-
- @Override
- public PlaybackState2 fromBundle_PlaybackState2(Context context, Bundle bundle) {
- return PlaybackState2Impl.fromBundle(context, bundle);
- }
-
- @Override
- public MediaPlaylistAgentProvider createMediaPlaylistAgent(Context context,
- MediaPlaylistAgent instance) {
- return new MediaPlaylistAgentImpl(context, instance);
+ public MediaPlaylistAgentProvider createMediaPlaylistAgent(MediaPlaylistAgent instance) {
+ return new MediaPlaylistAgentImpl(instance);
}
}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
index 7018844..ad8bb48 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -19,9 +19,12 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
+import android.support.annotation.GuardedBy;
import android.support.v4.widget.Space;
import android.support.v7.widget.ButtonBarLayout;
import android.util.AttributeSet;
@@ -35,45 +38,47 @@
import com.android.support.mediarouter.app.MediaRouteVolumeSlider;
import com.android.support.mediarouter.app.OverlayListView;
-public class ApiHelper {
- private static ApiHelper sInstance;
- private final Resources mLibResources;
- private final Theme mLibTheme;
+public final class ApiHelper {
+ private static ApplicationInfo sUpdatableInfo;
- public static ApiHelper getInstance() {
- return sInstance;
- }
+ @GuardedBy("this")
+ private static Theme sLibTheme;
- static void initialize(Resources libResources, Theme libTheme) {
- if (sInstance == null) {
- sInstance = new ApiHelper(libResources, libTheme);
+ private ApiHelper() { }
+
+ static void initialize(ApplicationInfo updatableInfo) {
+ if (sUpdatableInfo != null) {
+ throw new IllegalStateException("initialize should only be called once");
}
+
+ sUpdatableInfo = updatableInfo;
}
- private ApiHelper(Resources libResources, Theme libTheme) {
- mLibResources = libResources;
- mLibTheme = libTheme;
+ public static Resources getLibResources(Context context) {
+ return getLibTheme(context).getResources();
}
- public static Resources getLibResources() {
- return sInstance.mLibResources;
+ public static Theme getLibTheme(Context context) {
+ if (sLibTheme != null) return sLibTheme;
+
+ return getLibThemeSynchronized(context);
}
- public static Theme getLibTheme() {
- return sInstance.mLibTheme;
- }
-
- public static Theme getLibTheme(int themeId) {
- Theme theme = sInstance.mLibResources.newTheme();
+ public static Theme getLibTheme(Context context, int themeId) {
+ Theme theme = getLibResources(context).newTheme();
theme.applyStyle(themeId, true);
return theme;
}
public static LayoutInflater getLayoutInflater(Context context) {
- return getLayoutInflater(context, getLibTheme());
+ return getLayoutInflater(context, null);
}
public static LayoutInflater getLayoutInflater(Context context, Theme theme) {
+ if (theme == null) {
+ theme = getLibTheme(context);
+ }
+
// TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
LayoutInflater layoutInflater = LayoutInflater.from(context).cloneInContext(
new ContextThemeWrapper(context, theme));
@@ -106,7 +111,7 @@
}
public static View inflateLibLayout(Context context, int libResId) {
- return inflateLibLayout(context, getLibTheme(), libResId, null, false);
+ return inflateLibLayout(context, getLibTheme(context), libResId, null, false);
}
public static View inflateLibLayout(Context context, Theme theme, int libResId) {
@@ -115,8 +120,23 @@
public static View inflateLibLayout(Context context, Theme theme, int libResId,
@Nullable ViewGroup root, boolean attachToRoot) {
- try (XmlResourceParser parser = getLibResources().getLayout(libResId)) {
+ try (XmlResourceParser parser = getLibResources(context).getLayout(libResId)) {
return getLayoutInflater(context, theme).inflate(parser, root, attachToRoot);
}
}
+
+ private static synchronized Theme getLibThemeSynchronized(Context context) {
+ if (sLibTheme != null) return sLibTheme;
+
+ if (sUpdatableInfo == null) {
+ throw new IllegalStateException("initialize hasn't been called yet");
+ }
+
+ try {
+ return sLibTheme = context.getPackageManager()
+ .getResourcesForApplication(sUpdatableInfo).newTheme();
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
index fa94a81..fde8a63 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
@@ -130,7 +130,7 @@
mRouter = MediaRouter.getInstance(context);
mCallback = new MediaRouterCallback();
- Resources.Theme theme = ApiHelper.getLibResources().newTheme();
+ Resources.Theme theme = ApiHelper.getLibResources(context).newTheme();
theme.applyStyle(MediaRouterThemeHelper.getRouterThemeId(context), true);
TypedArray a = theme.obtainStyledAttributes(attrs,
R.styleable.MediaRouteButton, defStyleAttr, 0);
@@ -304,7 +304,8 @@
*/
void setCheatSheetEnabled(boolean enable) {
TooltipCompat.setTooltipText(this, enable
- ? ApiHelper.getLibResources().getString(R.string.mr_button_content_description)
+ ? ApiHelper.getLibResources(getContext())
+ .getString(R.string.mr_button_content_description)
: null);
}
@@ -547,7 +548,7 @@
} else {
resId = R.string.mr_cast_button_disconnected;
}
- setContentDescription(ApiHelper.getLibResources().getString(resId));
+ setContentDescription(ApiHelper.getLibResources(getContext()).getString(resId));
}
private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -604,7 +605,7 @@
@Override
protected Drawable doInBackground(Void... params) {
- return ApiHelper.getLibResources().getDrawable(mResId);
+ return ApiHelper.getLibResources(getContext()).getDrawable(mResId);
}
@Override
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
index 6e70eaf..cac64d9 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
@@ -99,8 +99,8 @@
public MediaRouteChooserDialog(Context context, int theme) {
// TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
- super(new ContextThemeWrapper(context,
- ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
+ super(new ContextThemeWrapper(context, ApiHelper.getLibTheme(context,
+ MediaRouterThemeHelper.getRouterThemeId(context))), theme);
context = getContext();
mRouter = MediaRouter.getInstance(context);
@@ -187,8 +187,8 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(ApiHelper.inflateLibLayout(getContext(),
- ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(getContext())),
+ setContentView(ApiHelper.inflateLibLayout(getContext(), ApiHelper.getLibTheme(getContext(),
+ MediaRouterThemeHelper.getRouterThemeId(getContext())),
R.layout.mr_chooser_dialog));
mRoutes = new ArrayList<>();
@@ -206,7 +206,7 @@
* Sets the width of the dialog. Also called when configuration changes.
*/
void updateLayout() {
- getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(),
+ getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(getContext()),
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@@ -263,7 +263,7 @@
public RouteAdapter(Context context, List<MediaRouter.RouteInfo> routes) {
super(context, 0, routes);
- TypedArray styledAttributes = ApiHelper.getLibTheme(
+ TypedArray styledAttributes = ApiHelper.getLibTheme(context,
MediaRouterThemeHelper.getRouterThemeId(context)).obtainStyledAttributes(
new int[] {
R.attr.mediaRouteDefaultIconDrawable,
@@ -294,7 +294,7 @@
View view = convertView;
if (view == null) {
view = ApiHelper.inflateLibLayout(getContext(),
- ApiHelper.getLibTheme(
+ ApiHelper.getLibTheme(getContext(),
MediaRouterThemeHelper.getRouterThemeId(getContext())),
R.layout.mr_chooser_list_item, parent, false);
}
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
index 269a6e9..060cfca 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
@@ -206,8 +206,8 @@
public MediaRouteControllerDialog(Context context, int theme) {
// TODO (b/72975976): Avoid to use ContextThemeWrapper with app context and lib theme.
- super(new ContextThemeWrapper(context,
- ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(context))), theme);
+ super(new ContextThemeWrapper(context, ApiHelper.getLibTheme(context,
+ MediaRouterThemeHelper.getRouterThemeId(context))), theme);
mContext = getContext();
mControllerCallback = new MediaControllerCallback();
@@ -215,7 +215,7 @@
mCallback = new MediaRouterCallback();
mRoute = mRouter.getSelectedRoute();
setMediaSession(mRouter.getMediaSessionToken());
- mVolumeGroupListPaddingTop = ApiHelper.getLibResources().getDimensionPixelSize(
+ mVolumeGroupListPaddingTop = ApiHelper.getLibResources(context).getDimensionPixelSize(
R.dimen.mr_controller_volume_group_list_padding_top);
mAccessibilityManager =
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
@@ -334,7 +334,7 @@
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
setContentView(ApiHelper.inflateLibLayout(mContext,
- ApiHelper.getLibTheme(MediaRouterThemeHelper.getRouterThemeId(mContext)),
+ ApiHelper.getLibTheme(mContext, MediaRouterThemeHelper.getRouterThemeId(mContext)),
R.layout.mr_controller_material_dialog_b));
// Remove the neutral button.
@@ -359,13 +359,13 @@
int color = MediaRouterThemeHelper.getButtonTextColor(mContext);
mDisconnectButton = findViewById(BUTTON_DISCONNECT_RES_ID);
mDisconnectButton.setText(
- ApiHelper.getLibResources().getString(R.string.mr_controller_disconnect));
+ ApiHelper.getLibResources(mContext).getString(R.string.mr_controller_disconnect));
mDisconnectButton.setTextColor(color);
mDisconnectButton.setOnClickListener(listener);
mStopCastingButton = findViewById(BUTTON_STOP_RES_ID);
mStopCastingButton.setText(
- ApiHelper.getLibResources().getString(R.string.mr_controller_stop_casting));
+ ApiHelper.getLibResources(mContext).getString(R.string.mr_controller_stop_casting));
mStopCastingButton.setTextColor(color);
mStopCastingButton.setOnClickListener(listener);
@@ -440,11 +440,11 @@
}
});
loadInterpolator();
- mGroupListAnimationDurationMs = ApiHelper.getLibResources().getInteger(
+ mGroupListAnimationDurationMs = ApiHelper.getLibResources(mContext).getInteger(
R.integer.mr_controller_volume_group_list_animation_duration_ms);
- mGroupListFadeInDurationMs = ApiHelper.getLibResources().getInteger(
+ mGroupListFadeInDurationMs = ApiHelper.getLibResources(mContext).getInteger(
R.integer.mr_controller_volume_group_list_fade_in_duration_ms);
- mGroupListFadeOutDurationMs = ApiHelper.getLibResources().getInteger(
+ mGroupListFadeOutDurationMs = ApiHelper.getLibResources(mContext).getInteger(
R.integer.mr_controller_volume_group_list_fade_out_duration_ms);
mCustomControlView = onCreateMediaControlView(savedInstanceState);
@@ -460,13 +460,13 @@
* Sets the width of the dialog. Also called when configuration changes.
*/
void updateLayout() {
- int width = MediaRouteDialogHelper.getDialogWidth();
+ int width = MediaRouteDialogHelper.getDialogWidth(mContext);
getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);
View decorView = getWindow().getDecorView();
mDialogContentWidth = width - decorView.getPaddingLeft() - decorView.getPaddingRight();
- Resources res = ApiHelper.getLibResources();
+ Resources res = ApiHelper.getLibResources(mContext);
mVolumeGroupListItemIconSize = res.getDimensionPixelSize(
R.dimen.mr_controller_volume_group_list_item_icon_size);
mVolumeGroupListItemHeight = res.getDimensionPixelSize(
@@ -991,16 +991,16 @@
if (mRoute.getPresentationDisplayId()
!= MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
// The user is currently casting screen.
- mTitleView.setText(ApiHelper.getLibResources().getString(
+ mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
R.string.mr_controller_casting_screen));
showTitle = true;
} else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
// Show "No media selected" as we don't yet know the playback state.
- mTitleView.setText(ApiHelper.getLibResources().getString(
+ mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
R.string.mr_controller_no_media_selected));
showTitle = true;
} else if (!hasTitle && !hasSubtitle) {
- mTitleView.setText(ApiHelper.getLibResources().getString(
+ mTitleView.setText(ApiHelper.getLibResources(mContext).getString(
R.string.mr_controller_no_info_available));
showTitle = true;
} else {
@@ -1223,7 +1223,8 @@
AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
event.setPackageName(mContext.getPackageName());
event.setClassName(getClass().getName());
- event.getText().add(ApiHelper.getLibResources().getString(actionDescResId));
+ event.getText().add(
+ ApiHelper.getLibResources(mContext).getString(actionDescResId));
mAccessibilityManager.sendAccessibilityEvent(event);
}
}
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
index 62c050b..9aabf7b 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogHelper.java
@@ -41,12 +41,13 @@
* The framework should set the dialog width properly, but somehow it doesn't work, hence
* duplicating a similar logic here to determine the appropriate dialog width.
*/
- public static int getDialogWidth() {
- DisplayMetrics metrics = ApiHelper.getLibResources().getDisplayMetrics();
+ public static int getDialogWidth(Context context) {
+ DisplayMetrics metrics = ApiHelper.getLibResources(context).getDisplayMetrics();
boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
TypedValue value = new TypedValue();
- ApiHelper.getLibResources().getValue(isPortrait ? R.dimen.mr_dialog_fixed_width_minor
+ ApiHelper.getLibResources(context).getValue(isPortrait
+ ? R.dimen.mr_dialog_fixed_width_minor
: R.dimen.mr_dialog_fixed_width_major, value, true);
if (value.type == TypedValue.TYPE_DIMENSION) {
return (int) value.getDimension(metrics);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
index defeedb..6a0a95a 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
@@ -51,9 +51,9 @@
public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mExpandAnimationDrawable = (AnimationDrawable)
- ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_expand);
+ ApiHelper.getLibResources(context).getDrawable(R.drawable.mr_group_expand);
mCollapseAnimationDrawable = (AnimationDrawable)
- ApiHelper.getLibResources().getDrawable(R.drawable.mr_group_collapse);
+ ApiHelper.getLibResources(context).getDrawable(R.drawable.mr_group_collapse);
ColorFilter filter = new PorterDuffColorFilter(
MediaRouterThemeHelper.getControllerColor(context, defStyleAttr),
@@ -62,9 +62,9 @@
mCollapseAnimationDrawable.setColorFilter(filter);
mExpandGroupDescription =
- ApiHelper.getLibResources().getString(R.string.mr_controller_expand_group);
+ ApiHelper.getLibResources(context).getString(R.string.mr_controller_expand_group);
mCollapseGroupDescription =
- ApiHelper.getLibResources().getString(R.string.mr_controller_collapse_group);
+ ApiHelper.getLibResources(context).getString(R.string.mr_controller_collapse_group);
setImageDrawable(mExpandAnimationDrawable.getFrame(0));
setContentDescription(mExpandGroupDescription);
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
index 33d92b4..a38491f 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
@@ -267,7 +267,7 @@
mCallbackObj = createCallbackObj();
mVolumeCallbackObj = createVolumeCallbackObj();
- Resources r = ApiHelper.getLibResources();
+ Resources r = ApiHelper.getLibResources(context);
mUserRouteCategoryObj = MediaRouterJellybean.createRouteCategory(
mRouterObj, r.getString(R.string.mr_user_route_category_name), false);
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 69febc2..4cdc41d 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -52,6 +52,7 @@
import com.android.support.mediarouter.media.MediaRouter;
import com.android.support.mediarouter.media.MediaRouteSelector;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
@@ -69,18 +70,42 @@
static final String KEY_VIDEO_TRACK_COUNT = "VideoTrackCount";
static final String KEY_AUDIO_TRACK_COUNT = "AudioTrackCount";
static final String KEY_SUBTITLE_TRACK_COUNT = "SubtitleTrackCount";
+ static final String KEY_PLAYBACK_SPEED = "PlaybackSpeed";
+ static final String KEY_SELECTED_AUDIO_INDEX = "SelectedAudioIndex";
+ static final String KEY_SELECTED_SUBTITLE_INDEX = "SelectedSubtitleIndex";
static final String EVENT_UPDATE_TRACK_STATUS = "UpdateTrackStatus";
// TODO: Remove this once integrating with MediaSession2 & MediaMetadata2
static final String KEY_STATE_IS_ADVERTISEMENT = "MediaTypeAdvertisement";
static final String EVENT_UPDATE_MEDIA_TYPE_STATUS = "UpdateMediaTypeStatus";
- // String for receiving command to show subtitle from MediaSession.
+ // String for sending command to show subtitle to MediaSession.
static final String COMMAND_SHOW_SUBTITLE = "showSubtitle";
- // String for receiving command to hide subtitle from MediaSession.
+ // String for sending command to hide subtitle to MediaSession.
static final String COMMAND_HIDE_SUBTITLE = "hideSubtitle";
// TODO: remove once the implementation is revised
public static final String COMMAND_SET_FULLSCREEN = "setFullscreen";
+ // String for sending command to select audio track to MediaSession.
+ static final String COMMAND_SELECT_AUDIO_TRACK = "SelectTrack";
+ // String for sending command to set playback speed to MediaSession.
+ static final String COMMAND_SET_PLAYBACK_SPEED = "SetPlaybackSpeed";
+ // String for sending command to mute audio to MediaSession.
+ static final String COMMAND_MUTE= "Mute";
+ // String for sending command to unmute audio to MediaSession.
+ static final String COMMAND_UNMUTE = "Unmute";
+
+ private static final int SETTINGS_MODE_AUDIO_TRACK = 0;
+ private static final int SETTINGS_MODE_PLAYBACK_SPEED = 1;
+ private static final int SETTINGS_MODE_HELP = 2;
+ private static final int SETTINGS_MODE_SUBTITLE_TRACK = 3;
+ private static final int SETTINGS_MODE_VIDEO_QUALITY = 4;
+ private static final int SETTINGS_MODE_MAIN = 5;
+ private static final int PLAYBACK_SPEED_1x_INDEX = 3;
+
+ private static final int SIZE_TYPE_EMBEDDED = 0;
+ private static final int SIZE_TYPE_FULL = 1;
+ // TODO: add support for Minimal size type.
+ private static final int SIZE_TYPE_MINIMAL = 2;
private static final int MAX_PROGRESS = 1000;
private static final int DEFAULT_PROGRESS_UPDATE_TIME_MS = 1000;
@@ -95,18 +120,25 @@
private MediaController.TransportControls mControls;
private PlaybackState mPlaybackState;
private MediaMetadata mMetadata;
- private ProgressBar mProgress;
- private TextView mEndTime, mCurrentTime;
- private TextView mTitleView;
- private TextView mAdSkipView, mAdRemainingView;
- private View mAdExternalLink;
- private View mRoot;
private int mDuration;
private int mPrevState;
- private int mPrevLeftBarWidth;
+ private int mPrevWidth;
+ private int mOriginalLeftBarWidth;
private int mVideoTrackCount;
private int mAudioTrackCount;
private int mSubtitleTrackCount;
+ private int mSettingsMode;
+ private int mSelectedSubtitleTrackIndex;
+ private int mSelectedAudioTrackIndex;
+ private int mSelectedVideoQualityIndex;
+ private int mSelectedSpeedIndex;
+ private int mEmbeddedSettingsItemWidth;
+ private int mFullSettingsItemWidth;
+ private int mEmbeddedSettingsItemHeight;
+ private int mFullSettingsItemHeight;
+ private int mSettingsWindowMargin;
+ private int mSizeType;
+ private int mOrientation;
private long mPlaybackActions;
private boolean mDragging;
private boolean mIsFullScreen;
@@ -115,45 +147,65 @@
private boolean mSubtitleIsEnabled;
private boolean mSeekAvailable;
private boolean mIsAdvertisement;
+ private boolean mIsMute;
+
+ // Relating to Title Bar View
+ private View mRoot;
+ private View mTitleBar;
+ private TextView mTitleView;
+ private View mAdExternalLink;
+ private ImageButton mBackButton;
+ private MediaRouteButton mRouteButton;
+ private MediaRouteSelector mRouteSelector;
+
+ // Relating to Center View
+ private ViewGroup mCenterView;
+ private View mTransportControls;
private ImageButton mPlayPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
+ // Relating to Progress Bar View
+ private ProgressBar mProgress;
+
+ // Relating to Bottom Bar Left View
+ private ViewGroup mBottomBarLeftView;
+ private ViewGroup mTimeView;
+ private TextView mEndTime;
+ private TextView mCurrentTime;
+ private TextView mAdSkipView;
+ private StringBuilder mFormatBuilder;
+ private Formatter mFormatter;
+
+ // Relating to Bottom Bar Right View
+ private ViewGroup mBottomBarRightView;
private ViewGroup mBasicControls;
+ private ViewGroup mExtraControls;
+ private ViewGroup mCustomButtons;
private ImageButton mSubtitleButton;
private ImageButton mFullScreenButton;
private ImageButton mOverflowButtonRight;
-
- private ViewGroup mExtraControls;
- private ViewGroup mCustomButtons;
private ImageButton mOverflowButtonLeft;
private ImageButton mMuteButton;
- private ImageButton mAspectRationButton;
+ private ImageButton mVideoQualityButton;
private ImageButton mSettingsButton;
+ private TextView mAdRemainingView;
+ // Relating to Settings List View
private ListView mSettingsListView;
private PopupWindow mSettingsWindow;
private SettingsAdapter mSettingsAdapter;
-
+ private SubSettingsAdapter mSubSettingsAdapter;
private List<String> mSettingsMainTextsList;
private List<String> mSettingsSubTextsList;
private List<Integer> mSettingsIconIdsList;
private List<String> mSubtitleDescriptionsList;
private List<String> mAudioTrackList;
private List<String> mVideoQualityList;
- private List<String> mPlaybackSpeedTextIdsList;
-
- private CharSequence mPlayDescription;
- private CharSequence mPauseDescription;
- private CharSequence mReplayDescription;
-
- private StringBuilder mFormatBuilder;
- private Formatter mFormatter;
-
- private MediaRouteButton mRouteButton;
- private MediaRouteSelector mRouteSelector;
+ private List<String> mPlaybackSpeedTextList;
+ private List<Float> mPlaybackSpeedList;
public MediaControlView2Impl(MediaControlView2 instance,
ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
@@ -163,10 +215,9 @@
@Override
public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- mResources = ApiHelper.getLibResources();
+ mResources = ApiHelper.getLibResources(mInstance.getContext());
// Inflate MediaControlView2 from XML
mRoot = makeControllerView();
- mRoot.addOnLayoutChangeListener(mTitleBarLayoutChangeListener);
mInstance.addView(mRoot);
}
@@ -217,15 +268,11 @@
}
break;
case MediaControlView2.BUTTON_NEXT:
- // TODO: this button is not visible unless its listener is manually set. Should this
- // function still be provided?
if (mNextButton != null) {
mNextButton.setVisibility(visibility);
}
break;
case MediaControlView2.BUTTON_PREV:
- // TODO: this button is not visible unless its listener is manually set. Should this
- // function still be provided?
if (mPrevButton != null) {
mPrevButton.setVisibility(visibility);
}
@@ -250,11 +297,6 @@
mMuteButton.setVisibility(visibility);
}
break;
- case MediaControlView2.BUTTON_ASPECT_RATIO:
- if (mAspectRationButton != null) {
- mAspectRationButton.setVisibility(visibility);
- }
- break;
case MediaControlView2.BUTTON_SETTINGS:
if (mSettingsButton != null) {
mSettingsButton.setVisibility(visibility);
@@ -289,6 +331,35 @@
}
@Override
+ public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+
+ if (mPrevWidth != mInstance.getMeasuredWidth()) {
+ int currWidth = mInstance.getMeasuredWidth();
+
+ int iconSize = mResources.getDimensionPixelSize(R.dimen.mcv2_full_icon_size);
+ int marginSize = mResources.getDimensionPixelSize(R.dimen.mcv2_icon_margin);
+ int bottomBarRightWidthMax = iconSize * 4 + marginSize * 8;
+
+ int fullWidth = mTransportControls.getWidth() + mTimeView.getWidth()
+ + bottomBarRightWidthMax;
+ // These views may not have been initialized yet.
+ if (mTransportControls.getWidth() == 0 || mTimeView.getWidth() == 0) {
+ return;
+ }
+ if (mSizeType == SIZE_TYPE_EMBEDDED && fullWidth <= currWidth) {
+ updateLayoutForSizeChange(SIZE_TYPE_FULL);
+ } else if (mSizeType == SIZE_TYPE_FULL && fullWidth > currWidth) {
+ updateLayoutForSizeChange(SIZE_TYPE_EMBEDDED);
+ }
+ // Dismiss SettingsWindow if it is showing.
+ mSettingsWindow.dismiss();
+ mPrevWidth = currWidth;
+ }
+ updateTitleBarLayout();
+ }
+
+ @Override
public void setEnabled_impl(boolean enabled) {
super.setEnabled_impl(enabled);
@@ -363,7 +434,8 @@
}
mPlaybackState = mController.getPlaybackState();
if (mPlaybackState != null) {
- return (int) (mPlaybackState.getBufferedPosition() * 100) / mDuration;
+ long bufferedPos = mPlaybackState.getBufferedPosition();
+ return (bufferedPos == -1) ? -1 : (int) (bufferedPos * 100 / mDuration);
}
return 0;
}
@@ -403,48 +475,50 @@
}
private void initControllerView(View v) {
- mPlayDescription = mResources.getText(R.string.lockscreen_play_button_content_description);
- mPauseDescription =
- mResources.getText(R.string.lockscreen_pause_button_content_description);
- mReplayDescription =
- mResources.getText(R.string.lockscreen_replay_button_content_description);
-
+ // Relating to Title Bar View
+ mTitleBar = v.findViewById(R.id.title_bar);
+ mTitleView = v.findViewById(R.id.title_text);
+ mAdExternalLink = v.findViewById(R.id.ad_external_link);
+ mBackButton = v.findViewById(R.id.back);
+ if (mBackButton != null) {
+ mBackButton.setOnClickListener(mBackListener);
+ }
mRouteButton = v.findViewById(R.id.cast);
- mPlayPauseButton = v.findViewById(R.id.pause);
- if (mPlayPauseButton != null) {
- mPlayPauseButton.requestFocus();
- mPlayPauseButton.setOnClickListener(mPlayPauseListener);
- mPlayPauseButton.setColorFilter(R.color.gray);
- mPlayPauseButton.setEnabled(false);
- }
- mFfwdButton = v.findViewById(R.id.ffwd);
- if (mFfwdButton != null) {
- mFfwdButton.setOnClickListener(mFfwdListener);
- mFfwdButton.setColorFilter(R.color.gray);
- mFfwdButton.setEnabled(false);
- }
- mRewButton = v.findViewById(R.id.rew);
- if (mRewButton != null) {
- mRewButton.setOnClickListener(mRewListener);
- mRewButton.setColorFilter(R.color.gray);
- mRewButton.setEnabled(false);
- }
- mNextButton = v.findViewById(R.id.next);
- if (mNextButton != null) {
- mNextButton.setOnClickListener(mNextListener);
- }
- mPrevButton = v.findViewById(R.id.prev);
- if (mPrevButton != null) {
- mPrevButton.setOnClickListener(mPrevListener);
+ // Relating to Center View
+ mCenterView = v.findViewById(R.id.center_view);
+ mTransportControls = inflateTransportControls(R.layout.embedded_transport_controls);
+ mCenterView.addView(mTransportControls);
+
+ // Relating to Progress Bar View
+ mProgress = v.findViewById(R.id.mediacontroller_progress);
+ if (mProgress != null) {
+ if (mProgress instanceof SeekBar) {
+ SeekBar seeker = (SeekBar) mProgress;
+ seeker.setOnSeekBarChangeListener(mSeekListener);
+ seeker.setProgressDrawable(mResources.getDrawable(R.drawable.custom_progress));
+ seeker.setThumb(mResources.getDrawable(R.drawable.custom_progress_thumb));
+ }
+ mProgress.setMax(MAX_PROGRESS);
}
+ // Relating to Bottom Bar Left View
+ mBottomBarLeftView = v.findViewById(R.id.bottom_bar_left);
+ mTimeView = v.findViewById(R.id.time);
+ mEndTime = v.findViewById(R.id.time_end);
+ mCurrentTime = v.findViewById(R.id.time_current);
+ mAdSkipView = v.findViewById(R.id.ad_skip_time);
+ mFormatBuilder = new StringBuilder();
+ mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
+
+ // Relating to Bottom Bar Right View
+ mBottomBarRightView = v.findViewById(R.id.bottom_bar_right);
mBasicControls = v.findViewById(R.id.basic_controls);
+ mExtraControls = v.findViewById(R.id.extra_controls);
+ mCustomButtons = v.findViewById(R.id.custom_buttons);
mSubtitleButton = v.findViewById(R.id.subtitle);
if (mSubtitleButton != null) {
mSubtitleButton.setOnClickListener(mSubtitleListener);
- mSubtitleButton.setColorFilter(R.color.gray);
- mSubtitleButton.setEnabled(false);
}
mFullScreenButton = v.findViewById(R.id.fullscreen);
if (mFullScreenButton != null) {
@@ -455,51 +529,45 @@
if (mOverflowButtonRight != null) {
mOverflowButtonRight.setOnClickListener(mOverflowRightListener);
}
-
- // TODO: should these buttons be shown as default?
- mExtraControls = v.findViewById(R.id.extra_controls);
- mCustomButtons = v.findViewById(R.id.custom_buttons);
mOverflowButtonLeft = v.findViewById(R.id.overflow_left);
if (mOverflowButtonLeft != null) {
mOverflowButtonLeft.setOnClickListener(mOverflowLeftListener);
}
mMuteButton = v.findViewById(R.id.mute);
- mAspectRationButton = v.findViewById(R.id.aspect_ratio);
+ if (mMuteButton != null) {
+ mMuteButton.setOnClickListener(mMuteButtonListener);
+ }
mSettingsButton = v.findViewById(R.id.settings);
if (mSettingsButton != null) {
mSettingsButton.setOnClickListener(mSettingsButtonListener);
}
-
- mProgress = v.findViewById(R.id.mediacontroller_progress);
- if (mProgress != null) {
- if (mProgress instanceof SeekBar) {
- SeekBar seeker = (SeekBar) mProgress;
- seeker.setOnSeekBarChangeListener(mSeekListener);
- }
- mProgress.setMax(MAX_PROGRESS);
+ mVideoQualityButton = v.findViewById(R.id.video_quality);
+ if (mVideoQualityButton != null) {
+ mVideoQualityButton.setOnClickListener(mVideoQualityListener);
}
-
- mTitleView = v.findViewById(R.id.title_text);
-
- mEndTime = v.findViewById(R.id.time);
- mCurrentTime = v.findViewById(R.id.time_current);
- mFormatBuilder = new StringBuilder();
- mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
-
- mAdSkipView = v.findViewById(R.id.ad_skip_time);
mAdRemainingView = v.findViewById(R.id.ad_remaining);
- mAdExternalLink = v.findViewById(R.id.ad_external_link);
+ // Relating to Settings List View
initializeSettingsLists();
mSettingsListView = (ListView) ApiHelper.inflateLibLayout(mInstance.getContext(),
R.layout.settings_list);
mSettingsAdapter = new SettingsAdapter(mSettingsMainTextsList, mSettingsSubTextsList,
- mSettingsIconIdsList, false);
+ mSettingsIconIdsList);
+ mSubSettingsAdapter = new SubSettingsAdapter(null, 0);
mSettingsListView.setAdapter(mSettingsAdapter);
mSettingsListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mSettingsListView.setOnItemClickListener(mSettingsItemClickListener);
- int width = mResources.getDimensionPixelSize(R.dimen.MediaControlView2_settings_width);
- mSettingsWindow = new PopupWindow(mSettingsListView, width,
+
+ mEmbeddedSettingsItemWidth = mResources.getDimensionPixelSize(
+ R.dimen.mcv2_embedded_settings_width);
+ mFullSettingsItemWidth = mResources.getDimensionPixelSize(R.dimen.mcv2_full_settings_width);
+ mEmbeddedSettingsItemHeight = mResources.getDimensionPixelSize(
+ R.dimen.mcv2_embedded_settings_height);
+ mFullSettingsItemHeight = mResources.getDimensionPixelSize(
+ R.dimen.mcv2_full_settings_height);
+ mSettingsWindowMargin = (-1) * mResources.getDimensionPixelSize(
+ R.dimen.mcv2_settings_offset);
+ mSettingsWindow = new PopupWindow(mSettingsListView, mEmbeddedSettingsItemWidth,
ViewGroup.LayoutParams.WRAP_CONTENT, true);
}
@@ -574,7 +642,13 @@
}
if (mProgress != null && currentPosition != mDuration) {
mProgress.setProgress(positionOnProgressBar);
- mProgress.setSecondaryProgress(getBufferPercentage() * 10);
+ // If the media is a local file, there is no need to set a buffer, so set secondary
+ // progress to maximum.
+ if (getBufferPercentage() < 0) {
+ mProgress.setSecondaryProgress(MAX_PROGRESS);
+ } else {
+ mProgress.setSecondaryProgress(getBufferPercentage() * 10);
+ }
}
if (mEndTime != null) {
@@ -623,12 +697,14 @@
mControls.pause();
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
} else {
mControls.play();
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPauseDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
}
}
@@ -664,7 +740,8 @@
if (mIsStopped) {
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
mIsStopped = false;
}
}
@@ -744,20 +821,30 @@
}
};
+ private final View.OnClickListener mBackListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // TODO: implement
+ }
+ };
+
private final View.OnClickListener mSubtitleListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (!mSubtitleIsEnabled) {
- mSubtitleButton.setImageDrawable(
- mResources.getDrawable(R.drawable.ic_media_subtitle_enabled, null));
- mController.sendCommand(MediaControlView2Impl.COMMAND_SHOW_SUBTITLE, null, null);
- mSubtitleIsEnabled = true;
- } else {
- mSubtitleButton.setImageDrawable(
- mResources.getDrawable(R.drawable.ic_media_subtitle_disabled, null));
- mController.sendCommand(MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, null);
- mSubtitleIsEnabled = false;
- }
+ mSettingsMode = SETTINGS_MODE_SUBTITLE_TRACK;
+ mSubSettingsAdapter.setTexts(mSubtitleDescriptionsList);
+ mSubSettingsAdapter.setCheckPosition(mSelectedSubtitleTrackIndex);
+ displaySettingsWindow(mSubSettingsAdapter);
+ }
+ };
+
+ private final View.OnClickListener mVideoQualityListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSettingsMode = SETTINGS_MODE_VIDEO_QUALITY;
+ mSubSettingsAdapter.setTexts(mVideoQualityList);
+ mSubSettingsAdapter.setCheckPosition(mSelectedVideoQualityIndex);
+ displaySettingsWindow(mSubSettingsAdapter);
}
};
@@ -797,20 +884,33 @@
}
};
+ private final View.OnClickListener mMuteButtonListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!mIsMute) {
+ mMuteButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_mute, null));
+ mMuteButton.setContentDescription(
+ mResources.getString(R.string.mcv2_muted_button_desc));
+ mIsMute = true;
+ mController.sendCommand(COMMAND_MUTE, null, null);
+ } else {
+ mMuteButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_unmute, null));
+ mMuteButton.setContentDescription(
+ mResources.getString(R.string.mcv2_unmuted_button_desc));
+ mIsMute = false;
+ mController.sendCommand(COMMAND_UNMUTE, null, null);
+ }
+ }
+ };
+
private final View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- mSettingsAdapter = new SettingsAdapter(mSettingsMainTextsList,
- mSettingsSubTextsList, mSettingsIconIdsList, false);
- mSettingsListView.setAdapter(mSettingsAdapter);
- int itemHeight = mResources.getDimensionPixelSize(
- R.dimen.MediaControlView2_settings_height);
- int totalHeight = mSettingsAdapter.getCount() * itemHeight;
- int margin = (-1) * mResources.getDimensionPixelSize(
- R.dimen.MediaControlView2_settings_offset);
- mSettingsWindow.dismiss();
- mSettingsWindow.showAsDropDown(mInstance, margin, margin - totalHeight,
- Gravity.BOTTOM | Gravity.RIGHT);
+ mSettingsMode = SETTINGS_MODE_MAIN;
+ mSettingsAdapter.setSubTexts(mSettingsSubTextsList);
+ displaySettingsWindow(mSettingsAdapter);
}
};
@@ -818,85 +918,81 @@
= new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- switch (position) {
- // change to identifiers
- case 0:
- // TODO: add additional subtitle track details
- mSubtitleDescriptionsList = new ArrayList<String>();
- mSubtitleDescriptionsList.add(mResources.getString(
- R.string.MediaControlView2_subtitle_off_text));
- for (int i = 0; i < mSubtitleTrackCount; i++) {
- String track = mResources.getString(
- R.string.MediaControlView2_subtitle_track_number_text, i + 1);
- mSubtitleDescriptionsList.add(track);
+ switch (mSettingsMode) {
+ case SETTINGS_MODE_MAIN:
+ if (position == SETTINGS_MODE_AUDIO_TRACK) {
+ mSubSettingsAdapter.setTexts(mAudioTrackList);
+ mSubSettingsAdapter.setCheckPosition(mSelectedAudioTrackIndex);
+ mSettingsMode = SETTINGS_MODE_AUDIO_TRACK;
+ } else if (position == SETTINGS_MODE_PLAYBACK_SPEED) {
+ mSubSettingsAdapter.setTexts(mPlaybackSpeedTextList);
+ mSubSettingsAdapter.setCheckPosition(mSelectedSpeedIndex);
+ mSettingsMode = SETTINGS_MODE_PLAYBACK_SPEED;
+ } else if (position == SETTINGS_MODE_HELP) {
+ // TODO: implement this.
+ mSettingsWindow.dismiss();
+ return;
}
- mSettingsAdapter = new SettingsAdapter(mSubtitleDescriptionsList, null,
- null, true);
+ displaySettingsWindow(mSubSettingsAdapter);
break;
- case 1:
- // TODO: add additional audio track details
- mAudioTrackList = new ArrayList<String>();
- mAudioTrackList.add(mResources.getString(
- R.string.MediaControlView2_audio_track_none_text));
- for (int i = 0; i < mAudioTrackCount; i++) {
- String track = mResources.getString(
- R.string.MediaControlView2_audio_track_number_text, i + 1);
- mAudioTrackList.add(track);
+ case SETTINGS_MODE_AUDIO_TRACK:
+ if (position != mSelectedAudioTrackIndex) {
+ mSelectedAudioTrackIndex = position;
+ if (mAudioTrackCount > 0) {
+ Bundle extra = new Bundle();
+ extra.putInt(KEY_SELECTED_AUDIO_INDEX, position);
+ mController.sendCommand(COMMAND_SELECT_AUDIO_TRACK, extra, null);
+ }
+ mSettingsSubTextsList.set(SETTINGS_MODE_AUDIO_TRACK,
+ mSubSettingsAdapter.getMainText(position));
}
- mSettingsAdapter = new SettingsAdapter(mAudioTrackList, null,
- null, true);
+ mSettingsWindow.dismiss();
break;
- case 2:
- // TODO: add support for multiple quality video tracks
- mSettingsAdapter = new SettingsAdapter(mVideoQualityList, null,
- null, true);
+ case SETTINGS_MODE_PLAYBACK_SPEED:
+ if (position != mSelectedSpeedIndex) {
+ mSelectedSpeedIndex = position;
+ Bundle extra = new Bundle();
+ extra.putFloat(KEY_PLAYBACK_SPEED, mPlaybackSpeedList.get(position));
+ mController.sendCommand(COMMAND_SET_PLAYBACK_SPEED, extra, null);
+ mSettingsSubTextsList.set(SETTINGS_MODE_PLAYBACK_SPEED,
+ mSubSettingsAdapter.getMainText(position));
+ }
+ mSettingsWindow.dismiss();
break;
- case 3:
- // TODO: implement code to reflect change in speed.
- mSettingsAdapter = new SettingsAdapter(mPlaybackSpeedTextIdsList, null,
- null, true);
+ case SETTINGS_MODE_HELP:
+ // TODO: implement this.
break;
- default:
- return;
- }
- mSettingsListView.setAdapter(mSettingsAdapter);
- int itemHeight = mResources.getDimensionPixelSize(
- R.dimen.MediaControlView2_settings_height);
- int totalHeight = mSettingsAdapter.getCount() * itemHeight;
- int margin = (-1) * mResources.getDimensionPixelSize(
- R.dimen.MediaControlView2_settings_offset);
- mSettingsWindow.dismiss();
- mSettingsWindow.showAsDropDown(mInstance, margin, margin - totalHeight,
- Gravity.BOTTOM | Gravity.RIGHT);
- }
- };
+ case SETTINGS_MODE_SUBTITLE_TRACK:
+ if (position != mSelectedSubtitleTrackIndex) {
+ mSelectedSubtitleTrackIndex = position;
+ if (position > 0) {
+ Bundle extra = new Bundle();
+ extra.putInt(KEY_SELECTED_SUBTITLE_INDEX, position - 1);
+ mController.sendCommand(
+ MediaControlView2Impl.COMMAND_SHOW_SUBTITLE, extra, null);
+ mSubtitleButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_subtitle_on, null));
+ mSubtitleButton.setContentDescription(
+ mResources.getString(R.string.mcv2_cc_is_on));
+ mSubtitleIsEnabled = true;
+ } else {
+ mController.sendCommand(
+ MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, null);
+ mSubtitleButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_subtitle_off, null));
+ mSubtitleButton.setContentDescription(
+ mResources.getString(R.string.mcv2_cc_is_off));
- // The title bar is made up of two separate LinearLayouts. If the sum of the two bars are
- // greater than the length of the title bar, reduce the size of the left bar (which makes the
- // TextView that contains the title of the media file shrink).
- private final View.OnLayoutChangeListener mTitleBarLayoutChangeListener
- = new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- if (mRoot != null) {
- int titleBarWidth = mRoot.findViewById(R.id.title_bar).getWidth();
-
- View leftBar = mRoot.findViewById(R.id.title_bar_left);
- View rightBar = mRoot.findViewById(R.id.title_bar_right);
- int leftBarWidth = leftBar.getWidth();
- int rightBarWidth = rightBar.getWidth();
-
- RelativeLayout.LayoutParams params =
- (RelativeLayout.LayoutParams) leftBar.getLayoutParams();
- if (leftBarWidth + rightBarWidth > titleBarWidth) {
- params.width = titleBarWidth - rightBarWidth;
- mPrevLeftBarWidth = leftBarWidth;
- } else if (leftBarWidth + rightBarWidth < titleBarWidth && mPrevLeftBarWidth != 0) {
- params.width = mPrevLeftBarWidth;
- mPrevLeftBarWidth = 0;
- }
- leftBar.setLayoutParams(params);
+ mSubtitleIsEnabled = false;
+ }
+ }
+ mSettingsWindow.dismiss();
+ break;
+ case SETTINGS_MODE_VIDEO_QUALITY:
+ // TODO: add support for video quality
+ mSelectedVideoQualityIndex = position;
+ mSettingsWindow.dismiss();
+ break;
}
}
};
@@ -919,13 +1015,37 @@
}
}
+ // The title bar is made up of two separate LinearLayouts. If the sum of the two bars are
+ // greater than the length of the title bar, reduce the size of the left bar (which makes the
+ // TextView that contains the title of the media file shrink).
+ private void updateTitleBarLayout() {
+ if (mTitleBar != null) {
+ int titleBarWidth = mTitleBar.getWidth();
+
+ View leftBar = mTitleBar.findViewById(R.id.title_bar_left);
+ View rightBar = mTitleBar.findViewById(R.id.title_bar_right);
+ int leftBarWidth = leftBar.getWidth();
+ int rightBarWidth = rightBar.getWidth();
+
+ RelativeLayout.LayoutParams params =
+ (RelativeLayout.LayoutParams) leftBar.getLayoutParams();
+ if (leftBarWidth + rightBarWidth > titleBarWidth) {
+ params.width = titleBarWidth - rightBarWidth;
+ mOriginalLeftBarWidth = leftBarWidth;
+ } else if (leftBarWidth + rightBarWidth < titleBarWidth && mOriginalLeftBarWidth != 0) {
+ params.width = mOriginalLeftBarWidth;
+ mOriginalLeftBarWidth = 0;
+ }
+ leftBar.setLayoutParams(params);
+ }
+ }
+
private void updateLayout() {
if (mIsAdvertisement) {
mRewButton.setVisibility(View.GONE);
mFfwdButton.setVisibility(View.GONE);
mPrevButton.setVisibility(View.GONE);
- mCurrentTime.setVisibility(View.GONE);
- mEndTime.setVisibility(View.GONE);
+ mTimeView.setVisibility(View.GONE);
mAdSkipView.setVisibility(View.VISIBLE);
mAdRemainingView.setVisibility(View.VISIBLE);
@@ -938,8 +1058,7 @@
mRewButton.setVisibility(View.VISIBLE);
mFfwdButton.setVisibility(View.VISIBLE);
mPrevButton.setVisibility(View.VISIBLE);
- mCurrentTime.setVisibility(View.VISIBLE);
- mEndTime.setVisibility(View.VISIBLE);
+ mTimeView.setVisibility(View.VISIBLE);
mAdSkipView.setVisibility(View.GONE);
mAdRemainingView.setVisibility(View.GONE);
@@ -952,81 +1071,142 @@
}
}
+ private void updateLayoutForSizeChange(int sizeType) {
+ mSizeType = sizeType;
+ RelativeLayout.LayoutParams params =
+ (RelativeLayout.LayoutParams) mTimeView.getLayoutParams();
+ switch (mSizeType) {
+ case SIZE_TYPE_EMBEDDED:
+ mBottomBarLeftView.removeView(mTransportControls);
+ mBottomBarLeftView.setVisibility(View.GONE);
+ mTransportControls = inflateTransportControls(R.layout.embedded_transport_controls);
+ mCenterView.addView(mTransportControls, 0);
+
+ if (params.getRule(RelativeLayout.LEFT_OF) != 0) {
+ params.removeRule(RelativeLayout.LEFT_OF);
+ params.addRule(RelativeLayout.RIGHT_OF, R.id.bottom_bar_left);
+ }
+ break;
+ case SIZE_TYPE_FULL:
+ mCenterView.removeView(mTransportControls);
+ mTransportControls = inflateTransportControls(R.layout.full_transport_controls);
+ mBottomBarLeftView.addView(mTransportControls, 0);
+ mBottomBarLeftView.setVisibility(View.VISIBLE);
+
+ if (params.getRule(RelativeLayout.RIGHT_OF) != 0) {
+ params.removeRule(RelativeLayout.RIGHT_OF);
+ params.addRule(RelativeLayout.LEFT_OF, R.id.bottom_bar_right);
+ }
+ break;
+ case SIZE_TYPE_MINIMAL:
+ // TODO: implement
+ break;
+ }
+ mTimeView.setLayoutParams(params);
+
+ if (isPlaying()) {
+ mPlayPauseButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
+ } else {
+ mPlayPauseButton.setImageDrawable(
+ mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
+ }
+ }
+
+ private View inflateTransportControls(int layoutId) {
+ View v = ApiHelper.inflateLibLayout(mInstance.getContext(), layoutId);
+ mPlayPauseButton = v.findViewById(R.id.pause);
+ if (mPlayPauseButton != null) {
+ mPlayPauseButton.requestFocus();
+ mPlayPauseButton.setOnClickListener(mPlayPauseListener);
+ }
+ mFfwdButton = v.findViewById(R.id.ffwd);
+ if (mFfwdButton != null) {
+ mFfwdButton.setOnClickListener(mFfwdListener);
+ }
+ mRewButton = v.findViewById(R.id.rew);
+ if (mRewButton != null) {
+ mRewButton.setOnClickListener(mRewListener);
+ }
+ // TODO: Add support for Next and Previous buttons
+ mNextButton = v.findViewById(R.id.next);
+ if (mNextButton != null) {
+ mNextButton.setOnClickListener(mNextListener);
+ mNextButton.setVisibility(View.GONE);
+ }
+ mPrevButton = v.findViewById(R.id.prev);
+ if (mPrevButton != null) {
+ mPrevButton.setOnClickListener(mPrevListener);
+ mPrevButton.setVisibility(View.GONE);
+ }
+ return v;
+ }
+
private void initializeSettingsLists() {
- if (mSettingsMainTextsList == null) {
- mSettingsMainTextsList = new ArrayList<String>();
- mSettingsMainTextsList.add(
- mResources.getString(R.string.MediaControlView2_subtitle_text));
- mSettingsMainTextsList.add(
- mResources.getString(R.string.MediaControlView2_audio_track_text));
- mSettingsMainTextsList.add(
- mResources.getString(R.string.MediaControlView2_video_quality_text));
- mSettingsMainTextsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_text));
- mSettingsMainTextsList.add(
- mResources.getString(R.string.MediaControlView2_help_text));
- }
+ mSettingsMainTextsList = new ArrayList<String>();
+ mSettingsMainTextsList.add(
+ mResources.getString(R.string.MediaControlView2_audio_track_text));
+ mSettingsMainTextsList.add(
+ mResources.getString(R.string.MediaControlView2_playback_speed_text));
+ mSettingsMainTextsList.add(
+ mResources.getString(R.string.MediaControlView2_help_text));
- // TODO: Update the following code to be dynamic.
- if (mSettingsSubTextsList == null) {
- mSettingsSubTextsList = new ArrayList<String>();
- mSettingsSubTextsList.add(
- mResources.getString(R.string.MediaControlView2_subtitle_off_text));
- mSettingsSubTextsList.add(
- mResources.getString(R.string.MediaControlView2_audio_track_none_text));
- mSettingsSubTextsList.add(
- mResources.getString(R.string.MediaControlView2_video_quality_auto_text));
- mSettingsSubTextsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_1x_text));
- mSettingsSubTextsList.add(RESOURCE_EMPTY);
- }
+ mSettingsSubTextsList = new ArrayList<String>();
+ mSettingsSubTextsList.add(
+ mResources.getString(R.string.MediaControlView2_audio_track_none_text));
+ mSettingsSubTextsList.add(
+ mResources.getStringArray(
+ R.array.MediaControlView2_playback_speeds)[PLAYBACK_SPEED_1x_INDEX]);
+ mSettingsSubTextsList.add(RESOURCE_EMPTY);
- if (mSettingsIconIdsList == null) {
- mSettingsIconIdsList = new ArrayList<Integer>();
- mSettingsIconIdsList.add(R.drawable.ic_closed_caption_off);
- mSettingsIconIdsList.add(R.drawable.ic_audiotrack);
- mSettingsIconIdsList.add(R.drawable.ic_high_quality);
- mSettingsIconIdsList.add(R.drawable.ic_play_circle_filled);
- mSettingsIconIdsList.add(R.drawable.ic_help);
- }
+ mSettingsIconIdsList = new ArrayList<Integer>();
+ mSettingsIconIdsList.add(R.drawable.ic_audiotrack);
+ mSettingsIconIdsList.add(R.drawable.ic_play_circle_filled);
+ mSettingsIconIdsList.add(R.drawable.ic_help);
- if (mSubtitleDescriptionsList == null) {
- mSubtitleDescriptionsList = new ArrayList<String>();
- mSubtitleDescriptionsList.add(
- mResources.getString(R.string.MediaControlView2_subtitle_off_text));
- }
+ mAudioTrackList = new ArrayList<String>();
+ mAudioTrackList.add(
+ mResources.getString(R.string.MediaControlView2_audio_track_none_text));
- if (mAudioTrackList == null) {
- mAudioTrackList = new ArrayList<String>();
- mAudioTrackList.add(
- mResources.getString(R.string.MediaControlView2_audio_track_none_text));
- }
+ mVideoQualityList = new ArrayList<String>();
+ mVideoQualityList.add(
+ mResources.getString(R.string.MediaControlView2_video_quality_auto_text));
- if (mVideoQualityList == null) {
- mVideoQualityList = new ArrayList<String>();
- mVideoQualityList.add(
- mResources.getString(R.string.MediaControlView2_video_quality_auto_text));
- }
+ mPlaybackSpeedTextList = new ArrayList<String>(Arrays.asList(
+ mResources.getStringArray(R.array.MediaControlView2_playback_speeds)));
+ // Select the "1x" speed as the default value.
+ mSelectedSpeedIndex = PLAYBACK_SPEED_1x_INDEX;
- if (mPlaybackSpeedTextIdsList == null) {
- mPlaybackSpeedTextIdsList = new ArrayList<String>();
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_0_25x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_0_5x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_0_75x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_1x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_1_25x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_1_5x_text));
- mPlaybackSpeedTextIdsList.add(
- mResources.getString(R.string.MediaControlView2_playback_speed_2x_text));
+ mPlaybackSpeedList = new ArrayList<Float>();
+ int[] speeds = mResources.getIntArray(R.array.speed_multiplied_by_100);
+ for (int i = 0; i < speeds.length; i++) {
+ float speed = (float) speeds[i] / 100.0f;
+ mPlaybackSpeedList.add(speed);
}
}
+ private void displaySettingsWindow(BaseAdapter adapter) {
+ // Set Adapter
+ mSettingsListView.setAdapter(adapter);
+
+ // Set width of window
+ int itemWidth = (mSizeType == SIZE_TYPE_EMBEDDED)
+ ? mEmbeddedSettingsItemWidth : mFullSettingsItemWidth;
+ mSettingsWindow.setWidth(itemWidth);
+
+ // Calculate height of window and show
+ int itemHeight = (mSizeType == SIZE_TYPE_EMBEDDED)
+ ? mEmbeddedSettingsItemHeight : mFullSettingsItemHeight;
+ int totalHeight = adapter.getCount() * itemHeight;
+ mSettingsWindow.dismiss();
+ mSettingsWindow.showAsDropDown(mInstance, mSettingsWindowMargin,
+ mSettingsWindowMargin - totalHeight, Gravity.BOTTOM | Gravity.RIGHT);
+ }
+
private class MediaControllerCallback extends MediaController.Callback {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -1041,19 +1221,22 @@
case PlaybackState.STATE_PLAYING:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPauseDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
mInstance.removeCallbacks(mUpdateProgress);
mInstance.post(mUpdateProgress);
break;
case PlaybackState.STATE_PAUSED:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
break;
case PlaybackState.STATE_STOPPED:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_replay_circle_filled, null));
- mPlayPauseButton.setContentDescription(mReplayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_replay_button_desc));
mIsStopped = true;
break;
default:
@@ -1065,16 +1248,13 @@
if (mPlaybackActions != mPlaybackState.getActions()) {
long newActions = mPlaybackState.getActions();
if ((newActions & PlaybackState.ACTION_PAUSE) != 0) {
- mPlayPauseButton.clearColorFilter();
- mPlayPauseButton.setEnabled(true);
+ mPlayPauseButton.setVisibility(View.VISIBLE);
}
if ((newActions & PlaybackState.ACTION_REWIND) != 0) {
- mRewButton.clearColorFilter();
- mRewButton.setEnabled(true);
+ mRewButton.setVisibility(View.VISIBLE);
}
if ((newActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
- mFfwdButton.clearColorFilter();
- mFfwdButton.setEnabled(true);
+ mFfwdButton.setVisibility(View.VISIBLE);
}
if ((newActions & PlaybackState.ACTION_SEEK_TO) != 0) {
mSeekAvailable = true;
@@ -1122,16 +1302,42 @@
switch (event) {
case EVENT_UPDATE_TRACK_STATUS:
mVideoTrackCount = extras.getInt(KEY_VIDEO_TRACK_COUNT);
+ // If there is one or more audio tracks, and this information has not been
+ // reflected into the Settings window yet, automatically check the first track.
+ // Otherwise, the Audio Track selection will be defaulted to "None".
mAudioTrackCount = extras.getInt(KEY_AUDIO_TRACK_COUNT);
- int newSubtitleTrackCount = extras.getInt(KEY_SUBTITLE_TRACK_COUNT);
- if (newSubtitleTrackCount > 0) {
- mSubtitleButton.clearColorFilter();
- mSubtitleButton.setEnabled(true);
+ mAudioTrackList = new ArrayList<String>();
+ if (mAudioTrackCount > 0) {
+ // TODO: add more text about track info.
+ for (int i = 0; i < mAudioTrackCount; i++) {
+ String track = mResources.getString(
+ R.string.MediaControlView2_audio_track_number_text, i + 1);
+ mAudioTrackList.add(track);
+ }
+ // Change sub text inside the Settings window.
+ mSettingsSubTextsList.set(SETTINGS_MODE_AUDIO_TRACK,
+ mAudioTrackList.get(0));
} else {
- mSubtitleButton.setColorFilter(R.color.gray);
+ mAudioTrackList.add(mResources.getString(
+ R.string.MediaControlView2_audio_track_none_text));
+ }
+
+ mSubtitleTrackCount = extras.getInt(KEY_SUBTITLE_TRACK_COUNT);
+ mSubtitleDescriptionsList = new ArrayList<String>();
+ if (mSubtitleTrackCount > 0) {
+ mSubtitleButton.setVisibility(View.VISIBLE);
+ mSubtitleButton.setEnabled(true);
+ mSubtitleDescriptionsList.add(mResources.getString(
+ R.string.MediaControlView2_subtitle_off_text));
+ for (int i = 0; i < mSubtitleTrackCount; i++) {
+ String track = mResources.getString(
+ R.string.MediaControlView2_subtitle_track_number_text, i + 1);
+ mSubtitleDescriptionsList.add(track);
+ }
+ } else {
+ mSubtitleButton.setVisibility(View.GONE);
mSubtitleButton.setEnabled(false);
}
- mSubtitleTrackCount = newSubtitleTrackCount;
break;
case EVENT_UPDATE_MEDIA_TYPE_STATUS:
boolean newStatus = extras.getBoolean(KEY_STATE_IS_ADVERTISEMENT);
@@ -1145,17 +1351,29 @@
}
private class SettingsAdapter extends BaseAdapter {
- List<Integer> mIconIds;
- List<String> mMainTexts;
- List<String> mSubTexts;
- boolean mIsCheckable;
+ private List<Integer> mIconIds;
+ private List<String> mMainTexts;
+ private List<String> mSubTexts;
public SettingsAdapter(List<String> mainTexts, @Nullable List<String> subTexts,
- @Nullable List<Integer> iconIds, boolean isCheckable) {
+ @Nullable List<Integer> iconIds) {
mMainTexts = mainTexts;
mSubTexts = subTexts;
mIconIds = iconIds;
- mIsCheckable = isCheckable;
+ }
+
+ public void updateSubTexts(List<String> subTexts) {
+ mSubTexts = subTexts;
+ notifyDataSetChanged();
+ }
+
+ public String getMainText(int position) {
+ if (mMainTexts != null) {
+ if (position < mMainTexts.size()) {
+ return mMainTexts.get(position);
+ }
+ }
+ return RESOURCE_EMPTY;
}
@Override
@@ -1179,12 +1397,17 @@
@Override
public View getView(int position, View convertView, ViewGroup container) {
- View row = ApiHelper.inflateLibLayout(mInstance.getContext(),
- R.layout.settings_list_item);
+ View row;
+ if (mSizeType == SIZE_TYPE_FULL) {
+ row = ApiHelper.inflateLibLayout(mInstance.getContext(),
+ R.layout.full_settings_list_item);
+ } else {
+ row = ApiHelper.inflateLibLayout(mInstance.getContext(),
+ R.layout.embedded_settings_list_item);
+ }
TextView mainTextView = (TextView) row.findViewById(R.id.main_text);
TextView subTextView = (TextView) row.findViewById(R.id.sub_text);
ImageView iconView = (ImageView) row.findViewById(R.id.icon);
- ImageView checkView = (ImageView) row.findViewById(R.id.check);
// Set main text
mainTextView.setText(mMainTexts.get(position));
@@ -1206,13 +1429,78 @@
// Otherwise, set main icon.
iconView.setImageDrawable(mResources.getDrawable(mIconIds.get(position), null));
}
+ return row;
+ }
- // Set check icon
- // TODO: make the following code dynamic
- if (!mIsCheckable) {
- checkView.setVisibility(View.GONE);
+ public void setSubTexts(List<String> subTexts) {
+ mSubTexts = subTexts;
+ }
+ }
+
+ // TODO: extend this class from SettingsAdapter
+ private class SubSettingsAdapter extends BaseAdapter {
+ private List<String> mTexts;
+ private int mCheckPosition;
+
+ public SubSettingsAdapter(List<String> texts, int checkPosition) {
+ mTexts = texts;
+ mCheckPosition = checkPosition;
+ }
+
+ public String getMainText(int position) {
+ if (mTexts != null) {
+ if (position < mTexts.size()) {
+ return mTexts.get(position);
+ }
+ }
+ return RESOURCE_EMPTY;
+ }
+
+ @Override
+ public int getCount() {
+ return (mTexts == null) ? 0 : mTexts.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // Auto-generated method stub--does not have any purpose here
+ // TODO: implement this.
+ return 0;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ // Auto-generated method stub--does not have any purpose here
+ // TODO: implement this.
+ return null;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup container) {
+ View row;
+ if (mSizeType == SIZE_TYPE_FULL) {
+ row = ApiHelper.inflateLibLayout(mInstance.getContext(),
+ R.layout.full_sub_settings_list_item);
+ } else {
+ row = ApiHelper.inflateLibLayout(mInstance.getContext(),
+ R.layout.embedded_sub_settings_list_item);
+ }
+ TextView textView = (TextView) row.findViewById(R.id.text);
+ ImageView checkView = (ImageView) row.findViewById(R.id.check);
+
+ textView.setText(mTexts.get(position));
+ if (position != mCheckPosition) {
+ checkView.setVisibility(View.INVISIBLE);
}
return row;
}
+
+ public void setTexts(List<String> texts) {
+ mTexts = texts;
+ }
+
+ public void setCheckPosition(int checkPosition) {
+ mCheckPosition = checkPosition;
+ }
}
}
diff --git a/packages/MediaComponents/src/com/android/widget/SubtitleView.java b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
index 9071967..67b2cd1 100644
--- a/packages/MediaComponents/src/com/android/widget/SubtitleView.java
+++ b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
@@ -18,13 +18,14 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleTrack.RenderingWidget;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
+import com.android.media.subtitle.SubtitleController.Anchor;
+import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
+
class SubtitleView extends FrameLayout implements Anchor {
private static final String TAG = "SubtitleView";
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 0bb659d..46ae359 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -24,18 +24,14 @@
import android.media.MediaMetadata;
import android.media.MediaPlayer2;
import android.media.MediaPlayer2.MediaPlayer2EventCallback;
+import android.media.MediaPlayer2.OnSubtitleDataListener;
import android.media.MediaPlayer2Impl;
-import android.media.Cea708CaptionRenderer;
-import android.media.ClosedCaptionRenderer;
+import android.media.SubtitleData;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.Metadata;
import android.media.PlaybackParams;
-import android.media.SRTRenderer;
-import android.media.SubtitleController;
import android.media.TimedText;
-import android.media.TtmlRenderer;
-import android.media.WebVttRenderer;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
@@ -59,6 +55,9 @@
import android.widget.VideoView2;
import com.android.media.RoutePlayer;
+import com.android.media.subtitle.ClosedCaptionRenderer;
+import com.android.media.subtitle.SubtitleController;
+import com.android.media.subtitle.SubtitleTrack;
import com.android.support.mediarouter.media.MediaItemStatus;
import com.android.support.mediarouter.media.MediaControlIntent;
import com.android.support.mediarouter.media.MediaRouter;
@@ -86,6 +85,7 @@
private static final int STATE_PLAYBACK_COMPLETED = 5;
private static final int INVALID_TRACK_INDEX = -1;
+ private static final float INVALID_SPEED = 0f;
private AccessibilityManager mAccessibilityManager;
private AudioManager mAudioManager;
@@ -123,7 +123,8 @@
private ArrayList<Integer> mVideoTrackIndices;
private ArrayList<Integer> mAudioTrackIndices;
- private ArrayList<Integer> mSubtitleTrackIndices;
+ private ArrayList<Pair<Integer, SubtitleTrack>> mSubtitleTrackIndices;
+ private SubtitleController mSubtitleController;
// selected video/audio/subtitle track index as MediaPlayer2 returns
private int mSelectedVideoTrackIndex;
@@ -137,6 +138,9 @@
// TODO: Remove mFallbackSpeed when integration with MediaPlayer2's new setPlaybackParams().
// Refer: https://docs.google.com/document/d/1nzAfns6i2hJ3RkaUre3QMT6wsDedJ5ONLiA_OOBFFX8/edit
private float mFallbackSpeed; // keep the original speed before 'pause' is called.
+ private float mVolumeLevelFloat;
+ private int mVolumeLevel;
+
private long mShowControllerIntervalMs;
private MediaRouter mMediaRouter;
@@ -631,18 +635,11 @@
mTextureView.setMediaPlayer(mMediaPlayer);
mCurrentView.assignSurfaceToMediaPlayer(mMediaPlayer);
- // TODO: create SubtitleController in MediaPlayer2, but we need
- // a context for the subtitle renderers
final Context context = mInstance.getContext();
- final SubtitleController controller = new SubtitleController(
- context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
- controller.registerRenderer(new WebVttRenderer(context));
- controller.registerRenderer(new TtmlRenderer(context));
- controller.registerRenderer(new Cea708CaptionRenderer(context));
- controller.registerRenderer(new ClosedCaptionRenderer(context));
- controller.registerRenderer(new SRTRenderer(context));
- mMediaPlayer.setSubtitleAnchor(
- controller, (SubtitleController.Anchor) mSubtitleView);
+ // TODO: Add timely firing logic for more accurate sync between CC and video frame
+ mSubtitleController = new SubtitleController(context);
+ mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
+ mSubtitleController.setAnchor((SubtitleController.Anchor) mSubtitleView);
Executor executor = new Executor() {
@Override
public void execute(Runnable runnable) {
@@ -651,9 +648,10 @@
};
mMediaPlayer.setMediaPlayer2EventCallback(executor, mMediaPlayer2Callback);
- mCurrentBufferPercentage = 0;
+ mCurrentBufferPercentage = -1;
mMediaPlayer.setDataSource(dsd);
mMediaPlayer.setAudioAttributes(mAudioAttributes);
+ mMediaPlayer.setOnSubtitleDataListener(mSubtitleListener);
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
@@ -753,8 +751,12 @@
&& mCurrentState != STATE_PREPARING) {
// TODO: this should be replaced with MediaPlayer2.getBufferedPosition() once it is
// implemented.
- mStateBuilder.setBufferedPosition(
- (long) (mCurrentBufferPercentage / 100.0) * mMediaPlayer.getDuration());
+ if (mCurrentBufferPercentage == -1) {
+ mStateBuilder.setBufferedPosition(-1);
+ } else {
+ mStateBuilder.setBufferedPosition(
+ (long) (mCurrentBufferPercentage / 100.0 * mMediaPlayer.getDuration()));
+ }
}
// Set PlaybackState for MediaSession
@@ -855,7 +857,8 @@
if (select) {
if (mSubtitleTrackIndices.size() > 0) {
// TODO: make this selection dynamic
- mSelectedSubtitleTrackIndex = mSubtitleTrackIndices.get(0);
+ mSelectedSubtitleTrackIndex = mSubtitleTrackIndices.get(0).first;
+ mSubtitleController.selectTrack(mSubtitleTrackIndices.get(0).second);
mMediaPlayer.selectTrack(mSelectedSubtitleTrackIndex);
mSubtitleView.setVisibility(View.VISIBLE);
}
@@ -873,6 +876,7 @@
mVideoTrackIndices = new ArrayList<>();
mAudioTrackIndices = new ArrayList<>();
mSubtitleTrackIndices = new ArrayList<>();
+ mSubtitleController.reset();
for (int i = 0; i < trackInfos.size(); ++i) {
int trackType = trackInfos.get(i).getTrackType();
if (trackType == MediaPlayer2.TrackInfo.MEDIA_TRACK_TYPE_VIDEO) {
@@ -881,9 +885,20 @@
mAudioTrackIndices.add(i);
} else if (trackType == MediaPlayer2.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
|| trackType == MediaPlayer2.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
- mSubtitleTrackIndices.add(i);
+ SubtitleTrack track = mSubtitleController.addTrack(trackInfos.get(i).getFormat());
+ if (track != null) {
+ mSubtitleTrackIndices.add(new Pair<>(i, track));
+ }
}
}
+ // Select first tracks as default
+ if (mVideoTrackIndices.size() > 0) {
+ mSelectedVideoTrackIndex = 0;
+ }
+ if (mAudioTrackIndices.size() > 0) {
+ mSelectedAudioTrackIndex = 0;
+ }
+
Bundle data = new Bundle();
data.putInt(MediaControlView2Impl.KEY_VIDEO_TRACK_COUNT, mVideoTrackIndices.size());
data.putInt(MediaControlView2Impl.KEY_AUDIO_TRACK_COUNT, mAudioTrackIndices.size());
@@ -894,6 +909,35 @@
mMediaSession.sendSessionEvent(MediaControlView2Impl.EVENT_UPDATE_TRACK_STATUS, data);
}
+ OnSubtitleDataListener mSubtitleListener =
+ new OnSubtitleDataListener() {
+ @Override
+ public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
+ if (DEBUG) {
+ Log.d(TAG, "onSubtitleData(): getTrackIndex: " + data.getTrackIndex()
+ + ", getCurrentPosition: " + mp.getCurrentPosition()
+ + ", getStartTimeUs(): " + data.getStartTimeUs()
+ + ", diff: "
+ + (data.getStartTimeUs()/1000 - mp.getCurrentPosition())
+ + "ms, getDurationUs(): " + data.getDurationUs()
+ );
+
+ }
+ final int index = data.getTrackIndex();
+ if (index != mSelectedSubtitleTrackIndex) {
+ Log.d(TAG, "onSubtitleData(): getTrackIndex: " + data.getTrackIndex()
+ + ", selected track index: " + mSelectedSubtitleTrackIndex);
+ return;
+ }
+ for (Pair<Integer, SubtitleTrack> p : mSubtitleTrackIndices) {
+ if (p.first == index) {
+ SubtitleTrack track = p.second;
+ track.onData(data);
+ }
+ }
+ }
+ };
+
MediaPlayer2EventCallback mMediaPlayer2Callback =
new MediaPlayer2EventCallback() {
@Override
@@ -1048,7 +1092,16 @@
} else {
switch (command) {
case MediaControlView2Impl.COMMAND_SHOW_SUBTITLE:
- mInstance.setSubtitleEnabled(true);
+ int subtitleIndex = args.getInt(
+ MediaControlView2Impl.KEY_SELECTED_SUBTITLE_INDEX,
+ INVALID_TRACK_INDEX);
+ if (subtitleIndex != INVALID_TRACK_INDEX) {
+ int subtitleTrackIndex = mSubtitleTrackIndices.get(subtitleIndex).first;
+ if (subtitleTrackIndex != mSelectedSubtitleTrackIndex) {
+ mSelectedSubtitleTrackIndex = subtitleTrackIndex;
+ mInstance.setSubtitleEnabled(true);
+ }
+ }
break;
case MediaControlView2Impl.COMMAND_HIDE_SUBTITLE:
mInstance.setSubtitleEnabled(false);
@@ -1060,6 +1113,32 @@
args.getBoolean(MediaControlView2Impl.ARGUMENT_KEY_FULLSCREEN));
}
break;
+ case MediaControlView2Impl.COMMAND_SELECT_AUDIO_TRACK:
+ int audioIndex = args.getInt(MediaControlView2Impl.KEY_SELECTED_AUDIO_INDEX,
+ INVALID_TRACK_INDEX);
+ if (audioIndex != INVALID_TRACK_INDEX) {
+ int audioTrackIndex = mAudioTrackIndices.get(audioIndex);
+ if (audioTrackIndex != mSelectedAudioTrackIndex) {
+ mSelectedAudioTrackIndex = audioTrackIndex;
+ mMediaPlayer.selectTrack(mSelectedAudioTrackIndex);
+ }
+ }
+ break;
+ case MediaControlView2Impl.COMMAND_SET_PLAYBACK_SPEED:
+ float speed = args.getFloat(
+ MediaControlView2Impl.KEY_PLAYBACK_SPEED, INVALID_SPEED);
+ if (speed != INVALID_SPEED && speed != mSpeed) {
+ mInstance.setSpeed(speed);
+ mSpeed = speed;
+ }
+ break;
+ case MediaControlView2Impl.COMMAND_MUTE:
+ mVolumeLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
+ break;
+ case MediaControlView2Impl.COMMAND_UNMUTE:
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mVolumeLevel, 0);
+ break;
}
}
showController();
diff --git a/packages/MediaComponents/tests/Android.mk b/packages/MediaComponents/tests/Android.mk
new file mode 100644
index 0000000..dddfd2a
--- /dev/null
+++ b/packages/MediaComponents/tests/Android.mk
@@ -0,0 +1,36 @@
+# Copyright 2018 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.test.runner.stubs \
+ android.test.base.stubs \
+ mockito-target-minus-junit4 \
+ junit
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := MediaComponentsTest
+
+LOCAL_INSTRUMENTATION_FOR := MediaComponents
+
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/MediaComponents/tests/AndroidManifest.xml b/packages/MediaComponents/tests/AndroidManifest.xml
new file mode 100644
index 0000000..7255265
--- /dev/null
+++ b/packages/MediaComponents/tests/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.tests">
+
+ <application android:label="Media API Test">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ To run the tests use the command:
+ "adb shell am instrument -w com.android.media.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.media.update"
+ android:label="Media API test" />
+
+</manifest>
diff --git a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
new file mode 100644
index 0000000..beb0848
--- /dev/null
+++ b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.DataSourceDesc;
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlayerBase;
+import android.media.MediaPlayerBase.PlayerEventCallback;
+import android.media.MediaPlaylistAgent;
+import android.media.MediaSession2;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.test.AndroidTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Tests {@link SessionPlaylistAgent}.
+ */
+public class SessionPlaylistAgentTest extends AndroidTestCase {
+ private static final String TAG = "SessionPlaylistAgentTest";
+ private static final int WAIT_TIME_MS = 1000;
+ private static final int INVALID_REPEAT_MODE = -100;
+ private static final int INVALID_SHUFFLE_MODE = -100;
+
+ private Handler mHandler;
+ private Executor mHandlerExecutor;
+
+ private Object mWaitLock = new Object();
+ private Context mContext;
+ private MediaSession2Impl mSessionImpl;
+ private MediaPlayerBase mPlayer;
+ private PlayerEventCallback mPlayerEventCallback;
+ private SessionPlaylistAgent mAgent;
+ private OnDataSourceMissingHelper mDataSourceHelper;
+ private MyPlaylistEventCallback mEventCallback;
+
+ public class MyPlaylistEventCallback extends MediaPlaylistAgent.PlaylistEventCallback {
+ boolean onPlaylistChangedCalled;
+ boolean onPlaylistMetadataChangedCalled;
+ boolean onRepeatModeChangedCalled;
+ boolean onShuffleModeChangedCalled;
+
+ private Object mWaitLock;
+
+ public MyPlaylistEventCallback(Object waitLock) {
+ mWaitLock = waitLock;
+ }
+
+ public void clear() {
+ onPlaylistChangedCalled = false;
+ onPlaylistMetadataChangedCalled = false;
+ onRepeatModeChangedCalled = false;
+ onShuffleModeChangedCalled = false;
+ }
+
+ public void onPlaylistChanged(MediaPlaylistAgent playlistAgent, List<MediaItem2> list,
+ MediaMetadata2 metadata) {
+ synchronized (mWaitLock) {
+ onPlaylistChangedCalled = true;
+ mWaitLock.notify();
+ }
+ }
+
+ public void onPlaylistMetadataChanged(MediaPlaylistAgent playlistAgent,
+ MediaMetadata2 metadata) {
+ synchronized (mWaitLock) {
+ onPlaylistMetadataChangedCalled = true;
+ mWaitLock.notify();
+ }
+ }
+
+ public void onRepeatModeChanged(MediaPlaylistAgent playlistAgent, int repeatMode) {
+ synchronized (mWaitLock) {
+ onRepeatModeChangedCalled = true;
+ mWaitLock.notify();
+ }
+ }
+
+ public void onShuffleModeChanged(MediaPlaylistAgent playlistAgent, int shuffleMode) {
+ synchronized (mWaitLock) {
+ onShuffleModeChangedCalled = true;
+ mWaitLock.notify();
+ }
+ }
+ }
+
+ public class MyDataSourceHelper implements OnDataSourceMissingHelper {
+ @Override
+ public DataSourceDesc onDataSourceMissing(MediaSession2 session, MediaItem2 item) {
+ if (item.getMediaId().contains("WITHOUT_DSD")) {
+ return null;
+ }
+ return new DataSourceDesc.Builder()
+ .setDataSource(getContext(), Uri.parse("dsd://test"))
+ .setMediaId(item.getMediaId())
+ .build();
+ }
+ }
+
+ public class MockPlayer extends MediaPlayerBase {
+ @Override
+ public void play() {
+ }
+
+ @Override
+ public void prepare() {
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void skipToNext() {
+ }
+
+ @Override
+ public void seekTo(long pos) {
+ }
+
+ @Override
+ public int getPlayerState() {
+ return 0;
+ }
+
+ @Override
+ public int getBufferingState() {
+ return 0;
+ }
+
+ @Override
+ public void setAudioAttributes(AudioAttributes attributes) {
+ }
+
+ @Override
+ public AudioAttributes getAudioAttributes() {
+ return null;
+ }
+
+ @Override
+ public void setDataSource(DataSourceDesc dsd) {
+ }
+
+ @Override
+ public void setNextDataSource(DataSourceDesc dsd) {
+ }
+
+ @Override
+ public void setNextDataSources(List<DataSourceDesc> dsds) {
+ }
+
+ @Override
+ public DataSourceDesc getCurrentDataSource() {
+ return null;
+ }
+
+ @Override
+ public void loopCurrent(boolean loop) {
+ }
+
+ @Override
+ public void setPlaybackSpeed(float speed) {
+ }
+
+ @Override
+ public void setPlayerVolume(float volume) {
+ }
+
+ @Override
+ public float getPlayerVolume() {
+ return 0;
+ }
+
+ @Override
+ public void registerPlayerEventCallback(Executor e, PlayerEventCallback cb) {
+ }
+
+ @Override
+ public void unregisterPlayerEventCallback(PlayerEventCallback cb) {
+ }
+
+ @Override
+ public void close() throws Exception {
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = getContext();
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+
+ HandlerThread handlerThread = new HandlerThread("SessionPlaylistAgent");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ mHandlerExecutor = (runnable) -> {
+ mHandler.post(runnable);
+ };
+
+ mPlayer = mock(MockPlayer.class);
+ doAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ mPlayerEventCallback = (PlayerEventCallback) args[1];
+ return null;
+ }).when(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
+
+ mSessionImpl = mock(MediaSession2Impl.class);
+ mDataSourceHelper = new MyDataSourceHelper();
+ mAgent = new SessionPlaylistAgent(mSessionImpl, mPlayer);
+ mAgent.setOnDataSourceMissingHelper(mDataSourceHelper);
+ mEventCallback = new MyPlaylistEventCallback(mWaitLock);
+ mAgent.registerPlaylistEventCallback(mHandlerExecutor, mEventCallback);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mHandler.getLooper().quitSafely();
+ mHandler = null;
+ mHandlerExecutor = null;
+ }
+
+ @Test
+ public void testSetAndGetShuflleMode() throws Exception {
+ int shuffleMode = mAgent.getShuffleMode();
+ if (shuffleMode != MediaPlaylistAgent.SHUFFLE_MODE_NONE) {
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_NONE);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onShuffleModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_NONE, mAgent.getShuffleMode());
+ }
+
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_ALL);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onShuffleModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_ALL, mAgent.getShuffleMode());
+
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_GROUP);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onShuffleModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_GROUP, mAgent.getShuffleMode());
+
+ // INVALID_SHUFFLE_MODE will not change the shuffle mode.
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setShuffleMode(INVALID_SHUFFLE_MODE);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertFalse(mEventCallback.onShuffleModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_GROUP, mAgent.getShuffleMode());
+ }
+
+ @Test
+ public void testSetAndGetRepeatMode() throws Exception {
+ int repeatMode = mAgent.getRepeatMode();
+ if (repeatMode != MediaPlaylistAgent.REPEAT_MODE_NONE) {
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onRepeatModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.REPEAT_MODE_NONE, mAgent.getRepeatMode());
+ }
+
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ONE);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onRepeatModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.REPEAT_MODE_ONE, mAgent.getRepeatMode());
+
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onRepeatModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.REPEAT_MODE_ALL, mAgent.getRepeatMode());
+
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_GROUP);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onRepeatModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.REPEAT_MODE_GROUP, mAgent.getRepeatMode());
+
+ // INVALID_SHUFFLE_MODE will not change the shuffle mode.
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setRepeatMode(INVALID_REPEAT_MODE);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertFalse(mEventCallback.onRepeatModeChangedCalled);
+ }
+ assertEquals(MediaPlaylistAgent.REPEAT_MODE_GROUP, mAgent.getRepeatMode());
+ }
+
+ @Test
+ public void testSetPlaylist() throws Exception {
+ int listSize = 10;
+ createAndSetPlaylist(10);
+ assertEquals(listSize, mAgent.getPlaylist().size());
+ assertEquals(0, mAgent.getCurShuffledIndex());
+ }
+
+ @Test
+ public void testSkipItems() throws Exception {
+ int listSize = 5;
+ List<MediaItem2> playlist = createAndSetPlaylist(listSize);
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
+ // Test skipToPlaylistItem
+ for (int i = listSize - 1; i >= 0; --i) {
+ mAgent.skipToPlaylistItem(playlist.get(i));
+ assertEquals(i, mAgent.getCurShuffledIndex());
+ }
+
+ // Test skipToNextItem
+ // curPlayPos = 0
+ for (int curPlayPos = 0; curPlayPos < listSize - 1; ++curPlayPos) {
+ mAgent.skipToNextItem();
+ assertEquals(curPlayPos + 1, mAgent.getCurShuffledIndex());
+ }
+ mAgent.skipToNextItem();
+ assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
+
+ // Test skipToPrevious
+ // curPlayPos = listSize - 1
+ for (int curPlayPos = listSize - 1; curPlayPos > 0; --curPlayPos) {
+ mAgent.skipToPreviousItem();
+ assertEquals(curPlayPos - 1, mAgent.getCurShuffledIndex());
+ }
+ mAgent.skipToPreviousItem();
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
+ // Test skipToPrevious with repeat mode all
+ // curPlayPos = 0
+ mAgent.skipToPreviousItem();
+ assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
+
+ // Test skipToNext with repeat mode all
+ // curPlayPos = listSize - 1
+ mAgent.skipToNextItem();
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ mAgent.skipToPreviousItem();
+ // curPlayPos = listSize - 1, nextPlayPos = 0
+ // Test next play pos after setting repeat mode none.
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
+ assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
+ }
+
+ @Test
+ public void testEditPlaylist() throws Exception {
+ int listSize = 5;
+ List<MediaItem2> playlist = createAndSetPlaylist(listSize);
+
+ // Test add item: [0 (cur), 1, 2, 3, 4] -> [0 (cur), 1, 5, 2, 3, 4]
+ mEventCallback.clear();
+ MediaItem2 item_5 = generateMediaItem(5);
+ synchronized (mWaitLock) {
+ playlist.add(2, item_5);
+ mAgent.addPlaylistItem(2, item_5);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+
+ mEventCallback.clear();
+ // Move current: [0 (cur), 1, 5, 2, 3, 4] -> [0, 1, 5 (cur), 2, 3, 4]
+ mAgent.skipToPlaylistItem(item_5);
+ // Remove current item: [0, 1, 5 (cur), 2, 3, 4] -> [0, 1, 2 (cur), 3, 4]
+ synchronized (mWaitLock) {
+ playlist.remove(item_5);
+ mAgent.removePlaylistItem(item_5);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(2, mAgent.getCurShuffledIndex());
+
+ // Remove previous item: [0, 1, 2 (cur), 3, 4] -> [0, 2 (cur), 3, 4]
+ mEventCallback.clear();
+ MediaItem2 previousItem = playlist.get(1);
+ synchronized (mWaitLock) {
+ playlist.remove(previousItem);
+ mAgent.removePlaylistItem(previousItem);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Remove next item: [0, 2 (cur), 3, 4] -> [0, 2 (cur), 4]
+ mEventCallback.clear();
+ MediaItem2 nextItem = playlist.get(2);
+ synchronized (mWaitLock) {
+ playlist.remove(nextItem);
+ mAgent.removePlaylistItem(nextItem);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Replace item: [0, 2 (cur), 4] -> [0, 2 (cur), 5]
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.set(2, item_5);
+ mAgent.replacePlaylistItem(2, item_5);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Move last and remove the last item: [0, 2 (cur), 5] -> [0, 2, 5 (cur)] -> [0, 2 (cur)]
+ MediaItem2 lastItem = playlist.get(1);
+ mAgent.skipToPlaylistItem(lastItem);
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.remove(lastItem);
+ mAgent.removePlaylistItem(lastItem);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Remove all items
+ for (int i = playlist.size() - 1; i >= 0; --i) {
+ MediaItem2 item = playlist.get(i);
+ mAgent.skipToPlaylistItem(item);
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.remove(item);
+ mAgent.removePlaylistItem(item);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ }
+ assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
+ }
+
+
+ @Test
+ public void testPlaylistWithInvalidItem() throws Exception {
+ int listSize = 2;
+ List<MediaItem2> playlist = createAndSetPlaylist(listSize);
+
+ // Add item: [0 (cur), 1] -> [0 (cur), 3 (no_dsd), 1]
+ mEventCallback.clear();
+ MediaItem2 invalidItem2 = generateMediaItemWithoutDataSourceDesc(2);
+ synchronized (mWaitLock) {
+ playlist.add(1, invalidItem2);
+ mAgent.addPlaylistItem(1, invalidItem2);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ // Test skip to next item: [0 (cur), 2 (no_dsd), 1] -> [0, 2 (no_dsd), 1 (cur)]
+ mAgent.skipToNextItem();
+ assertEquals(2, mAgent.getCurShuffledIndex());
+
+ // Test skip to previous item: [0, 2 (no_dsd), 1 (cur)] -> [0 (cur), 2 (no_dsd), 1]
+ mAgent.skipToPreviousItem();
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ // Remove current item: [0 (cur), 2 (no_dsd), 1] -> [2 (no_dsd), 1 (cur)]
+ mEventCallback.clear();
+ MediaItem2 item = playlist.get(0);
+ synchronized (mWaitLock) {
+ playlist.remove(item);
+ mAgent.removePlaylistItem(item);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Remove current item: [2 (no_dsd), 1 (cur)] -> [2 (no_dsd)]
+ mEventCallback.clear();
+ item = playlist.get(1);
+ synchronized (mWaitLock) {
+ playlist.remove(item);
+ mAgent.removePlaylistItem(item);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
+
+ // Add invalid item: [2 (no_dsd)] -> [0 (no_dsd), 2 (no_dsd)]
+ MediaItem2 invalidItem0 = generateMediaItemWithoutDataSourceDesc(0);
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.add(0, invalidItem0);
+ mAgent.addPlaylistItem(0, invalidItem0);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
+
+ // Add valid item: [0 (no_dsd), 2 (no_dsd)] -> [0 (no_dsd), 1, 2 (no_dsd)]
+ MediaItem2 invalidItem1 = generateMediaItem(1);
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.add(1, invalidItem1);
+ mAgent.addPlaylistItem(1, invalidItem1);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(1, mAgent.getCurShuffledIndex());
+
+ // Replace the valid item with an invalid item:
+ // [0 (no_dsd), 1 (cur), 2 (no_dsd)] -> [0 (no_dsd), 3 (no_dsd), 2 (no_dsd)]
+ MediaItem2 invalidItem3 = generateMediaItemWithoutDataSourceDesc(3);
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ playlist.set(1, invalidItem3);
+ mAgent.replacePlaylistItem(1, invalidItem3);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ assertPlaylistEquals(playlist, mAgent.getPlaylist());
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+ }
+
+ @Test
+ public void testPlaylistAfterOnCurrentDataSourceChanged() throws Exception {
+ int listSize = 2;
+ verify(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
+
+ createAndSetPlaylist(listSize);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(1, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.skipToNextItem();
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ONE);
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(1, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+ }
+
+ private List<MediaItem2> createAndSetPlaylist(int listSize) throws Exception {
+ List<MediaItem2> items = new ArrayList<>();
+ for (int i = 0; i < listSize; ++i) {
+ items.add(generateMediaItem(i));
+ }
+ mEventCallback.clear();
+ synchronized (mWaitLock) {
+ mAgent.setPlaylist(items, null);
+ mWaitLock.wait(WAIT_TIME_MS);
+ assertTrue(mEventCallback.onPlaylistChangedCalled);
+ }
+ return items;
+ }
+
+ private void assertPlaylistEquals(List<MediaItem2> expected, List<MediaItem2> actual) {
+ if (expected == actual) {
+ return;
+ }
+ assertTrue(expected != null && actual != null);
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); ++i) {
+ assertTrue(expected.get(i).equals(actual.get(i)));
+ }
+ }
+
+ private MediaItem2 generateMediaItemWithoutDataSourceDesc(int key) {
+ return new MediaItem2.Builder(0)
+ .setMediaId("TEST_MEDIA_ID_WITHOUT_DSD_" + key)
+ .build();
+ }
+
+ private MediaItem2 generateMediaItem(int key) {
+ return new MediaItem2.Builder(0)
+ .setMediaId("TEST_MEDIA_ID_" + key)
+ .build();
+ }
+}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8033382..ea06b6c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3139,16 +3139,21 @@
bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId);
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
&desc, enabled, &lStatus, pinned);
- if (handle != 0 && id != NULL) {
- *id = handle->id();
- }
- if (handle == 0) {
+ if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
// remove local strong reference to Client with mClientLock held
Mutex::Autolock _cl(mClientLock);
client.clear();
+ } else {
+ // handle must be valid here, but check again to be safe.
+ if (handle.get() != nullptr && id != nullptr) *id = handle->id();
}
}
+ if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+ // handle must be cleared outside lock.
+ handle.clear();
+ }
+
Exit:
*status = lStatus;
return handle;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3134323..62e9fe7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1360,7 +1360,7 @@
if (chainCreated) {
removeEffectChain_l(chain);
}
- handle.clear();
+ // handle must be cleared by caller to avoid deadlock.
}
*status = lStatus;
@@ -3481,7 +3481,8 @@
if (diff > 0) {
// notify of throttle end on debug log
// but prevent spamming for bluetooth
- ALOGD_IF(!audio_is_a2dp_out_device(outDevice()),
+ ALOGD_IF(!audio_is_a2dp_out_device(outDevice()) &&
+ !audio_is_hearing_aid_out_device(outDevice()),
"mixer(%p) throttle end: throttle time(%u)", this, diff);
mThreadThrottleEndMs = mThreadThrottleTimeMs;
}
@@ -8523,7 +8524,11 @@
audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
: MmapThread(audioFlinger, id, hwDev, output->stream, outDevice, inDevice, systemReady),
mStreamType(AUDIO_STREAM_MUSIC),
- mStreamVolume(1.0), mStreamMute(false), mOutput(output)
+ mStreamVolume(1.0),
+ mStreamMute(false),
+ mHalVolFloat(-1.0f), // Initialize to illegal value so it always gets set properly later.
+ mNoCallbackWarningCount(0),
+ mOutput(output)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
@@ -8631,7 +8636,6 @@
}
if (volume != mHalVolFloat) {
- mHalVolFloat = volume;
// Convert volumes from float to 8.24
uint32_t vol = (uint32_t)(volume * (1 << 24));
@@ -8644,7 +8648,10 @@
volume = (float)vol / (1 << 24);
}
// Try to use HW volume control and fall back to SW control if not implemented
- if (mOutput->stream->setVolume(volume, volume) != NO_ERROR) {
+ if (mOutput->stream->setVolume(volume, volume) == NO_ERROR) {
+ mHalVolFloat = volume; // HW volume control worked, so update value.
+ mNoCallbackWarningCount = 0;
+ } else {
sp<MmapStreamCallback> callback = mCallback.promote();
if (callback != 0) {
int channelCount;
@@ -8658,8 +8665,13 @@
values.add(volume);
}
callback->onVolumeChanged(mChannelMask, values);
+ mHalVolFloat = volume; // SW volume control worked, so update value.
+ mNoCallbackWarningCount = 0;
} else {
- ALOGW("Could not set MMAP stream volume: no volume callback!");
+ if (mNoCallbackWarningCount < kMaxNoCallbackWarnings) {
+ ALOGW("Could not set MMAP stream volume: no volume callback!");
+ mNoCallbackWarningCount++;
+ }
}
}
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ae14ac1..7cd46a7 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1666,6 +1666,8 @@
bool mMasterMute;
bool mStreamMute;
float mHalVolFloat;
+ int32_t mNoCallbackWarningCount;
+ static constexpr int32_t kMaxNoCallbackWarnings = 5;
AudioStreamOut* mOutput;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 78a184b..5e5d38b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -203,6 +203,16 @@
*/
audio_io_handle_t getA2dpOutput() const;
+ /**
+ * returns true if primary HAL supports A2DP Offload
+ */
+ bool isA2dpOffloadedOnPrimary() const;
+
+ /**
+ * returns true if A2DP is supported (either via hardware offload or software encoding)
+ */
+ bool isA2dpSupported() const;
+
sp<SwAudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
sp<SwAudioOutputDescriptor> getPrimaryOutput() const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index caaa0f7..294a2a6 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -645,6 +645,29 @@
return 0;
}
+bool SwAudioOutputCollection::isA2dpOffloadedOnPrimary() const
+{
+ sp<SwAudioOutputDescriptor> primaryOutput = getPrimaryOutput();
+
+ if ((primaryOutput != NULL) && (primaryOutput->mProfile != NULL)
+ && (primaryOutput->mProfile->mModule != NULL)) {
+ sp<HwModule> primaryHwModule = primaryOutput->mProfile->mModule;
+ Vector <sp<IOProfile>> primaryHwModuleOutputProfiles =
+ primaryHwModule->getOutputProfiles();
+ for (size_t i = 0; i < primaryHwModuleOutputProfiles.size(); i++) {
+ if (primaryHwModuleOutputProfiles[i]->supportDevice(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool SwAudioOutputCollection::isA2dpSupported() const
+{
+ return (isA2dpOffloadedOnPrimary() || (getA2dpOutput() != 0));
+}
+
sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getPrimaryOutput() const
{
for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h b/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
index 31b7e0f..e4fd176 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
@@ -62,7 +62,8 @@
[AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
[AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
- [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround"
+ [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
+ [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
};
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index e08583c..be7f7ec 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -154,6 +154,13 @@
}
mForceUse[usage] = config;
break;
+ case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+ if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_VIBRATE_RINGING", config);
+ return BAD_VALUE;
+ }
+ mForceUse[usage] = config;
+ break;
default:
ALOGW("setForceUse() invalid usage %d", usage);
break; // TODO return BAD_VALUE?
@@ -343,7 +350,7 @@
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (outputs.getA2dpOutput() != 0)) {
+ outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
@@ -377,7 +384,7 @@
// A2DP speaker when forcing to speaker output
if (!isInCall() &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (outputs.getA2dpOutput() != 0)) {
+ outputs.isA2dpSupported()) {
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
}
@@ -423,8 +430,7 @@
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
- if (((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO)) {
+ if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
uint32_t device2 = AUDIO_DEVICE_NONE;
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device2 == AUDIO_DEVICE_NONE) {
@@ -433,10 +439,23 @@
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
}
-
- if (device2 != AUDIO_DEVICE_NONE) {
- device |= device2;
- break;
+ // Use ONLY Bluetooth SCO output when ringing in vibration mode
+ if (!((mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
+ if (mForceUse[AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING]
+ == AUDIO_POLICY_FORCE_BT_SCO) {
+ if (device2 != AUDIO_DEVICE_NONE) {
+ device = device2;
+ break;
+ }
+ }
+ }
+ // Use both Bluetooth SCO and phone default output when ringing in normal mode
+ if (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) {
+ if (device2 != AUDIO_DEVICE_NONE) {
+ device |= device2;
+ break;
+ }
}
}
// The second device used for sonification is the same as the device used by media strategy
@@ -494,7 +513,7 @@
}
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (outputs.getA2dpOutput() != 0)) {
+ outputs.isA2dpSupported()) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 42b199a..92a2030 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -26,6 +26,7 @@
#define AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH 128
#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
+#define AUDIO_POLICY_A2DP_OFFLOAD_XML_CONFIG_FILE_NAME "audio_policy_a2dp_offload_configuration.xml"
#include <inttypes.h>
#include <math.h>
@@ -1265,6 +1266,11 @@
// We do not introduce additional delay here.
}
+ if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
+ }
+
return NO_ERROR;
}
@@ -1365,6 +1371,12 @@
// update the outputs if stopping one with a stream that can affect notification routing
handleNotificationRoutingForStream(stream);
}
+
+ if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ setStrategyMute(STRATEGY_SONIFICATION, false, outputDesc);
+ }
+
if (stream == AUDIO_STREAM_MUSIC) {
selectOutputForMusicEffects();
}
@@ -3517,11 +3529,14 @@
for (int i = 0; i < kConfigLocationListSize; i++) {
PolicySerializer serializer;
+ bool use_a2dp_offload_config =
+ property_get_bool("persist.bluetooth.a2dp_offload.enable", false);
snprintf(audioPolicyXmlConfigFile,
sizeof(audioPolicyXmlConfigFile),
"%s/%s",
kConfigLocationList[i],
- AUDIO_POLICY_XML_CONFIG_FILE_NAME);
+ use_a2dp_offload_config ? AUDIO_POLICY_A2DP_OFFLOAD_XML_CONFIG_FILE_NAME :
+ AUDIO_POLICY_XML_CONFIG_FILE_NAME);
ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
if (ret == NO_ERROR) {
break;
@@ -4381,7 +4396,7 @@
void AudioPolicyManager::checkA2dpSuspend()
{
audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput();
- if (a2dpOutput == 0) {
+ if (a2dpOutput == 0 || mOutputs.isA2dpOffloadedOnPrimary()) {
mA2dpSuspended = false;
return;
}
@@ -5126,7 +5141,8 @@
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_USB_HEADSET)) &&
+ AUDIO_DEVICE_OUT_USB_HEADSET |
+ AUDIO_DEVICE_OUT_HEARING_AID)) &&
((stream_strategy == STRATEGY_SONIFICATION)
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
|| (stream == AUDIO_STREAM_SYSTEM)
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 90a5a0f..5d90408 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -273,7 +273,7 @@
void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
const String8& regId, int32_t state)
{
- if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
+ if (mAudioPolicyServiceClient != 0 && (mUid % AID_USER_OFFSET) < AID_APP_START) {
mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
}
}
@@ -283,7 +283,7 @@
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
- if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
+ if (mAudioPolicyServiceClient != 0 && (mUid % AID_USER_OFFSET) < AID_APP_START) {
mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ad63899..9ed6d73 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1550,6 +1550,9 @@
switch(eventId) {
case ICameraService::EVENT_USER_SWITCHED: {
+ // Try to register for UID policy updates, in case we're recovering
+ // from a system server crash
+ mUidPolicy->registerSelf();
doUserSwitch(/*newUserIds*/ args);
break;
}
@@ -1996,14 +1999,17 @@
// A reference count is kept to determine when we will actually release the
// media players.
-MediaPlayer* CameraService::newMediaPlayer(const char *file) {
- MediaPlayer* mp = new MediaPlayer();
- if (mp->setDataSource(NULL /* httpService */, file, NULL) == NO_ERROR) {
+sp<MediaPlayer> CameraService::newMediaPlayer(const char *file) {
+ sp<MediaPlayer> mp = new MediaPlayer();
+ status_t error;
+ if ((error = mp->setDataSource(NULL /* httpService */, file, NULL)) == NO_ERROR) {
mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
- mp->prepare();
- } else {
+ error = mp->prepare();
+ }
+ if (error != NO_ERROR) {
ALOGE("Failed to load CameraService sounds: %s", file);
- delete mp;
+ mp->disconnect();
+ mp.clear();
return nullptr;
}
return mp;
@@ -2365,17 +2371,31 @@
// ----------------------------------------------------------------------------
void CameraService::UidPolicy::registerSelf() {
+ Mutex::Autolock _l(mUidLock);
+
ActivityManager am;
+ if (mRegistered) return;
am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
| ActivityManager::UID_OBSERVER_IDLE
| ActivityManager::UID_OBSERVER_ACTIVE,
ActivityManager::PROCESS_STATE_UNKNOWN,
String16("cameraserver"));
+ status_t res = am.linkToDeath(this);
+ if (res == OK) {
+ mRegistered = true;
+ ALOGV("UidPolicy: Registered with ActivityManager");
+ }
}
void CameraService::UidPolicy::unregisterSelf() {
+ Mutex::Autolock _l(mUidLock);
+
ActivityManager am;
am.unregisterUidObserver(this);
+ am.unlinkToDeath(this);
+ mRegistered = false;
+ mActiveUids.clear();
+ ALOGV("UidPolicy: Unregistered with ActivityManager");
}
void CameraService::UidPolicy::onUidGone(uid_t uid, bool disabled) {
@@ -2404,17 +2424,14 @@
}
bool CameraService::UidPolicy::isUidActive(uid_t uid) {
- // Non-app UIDs are considered always active
- if (uid < FIRST_APPLICATION_UID) {
- return true;
- }
Mutex::Autolock _l(mUidLock);
return isUidActiveLocked(uid);
}
bool CameraService::UidPolicy::isUidActiveLocked(uid_t uid) {
// Non-app UIDs are considered always active
- if (uid < FIRST_APPLICATION_UID) {
+ // If activity manager is unreachable, assume everything is active
+ if (uid < FIRST_APPLICATION_UID || !mRegistered) {
return true;
}
auto it = mOverrideUids.find(uid);
@@ -2432,6 +2449,13 @@
updateOverrideUid(uid, false, false);
}
+void CameraService::UidPolicy::binderDied(const wp<IBinder>& /*who*/) {
+ Mutex::Autolock _l(mUidLock);
+ ALOGV("UidPolicy: ActivityManager has died");
+ mRegistered = false;
+ mActiveUids.clear();
+}
+
void CameraService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
bool wasActive = false;
bool isActive = false;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3812925..a7a9264 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -518,10 +518,10 @@
// Observer for UID lifecycle enforcing that UIDs in idle
// state cannot use the camera to protect user privacy.
- class UidPolicy : public BnUidObserver {
+ class UidPolicy : public BnUidObserver, public virtual IBinder::DeathRecipient {
public:
explicit UidPolicy(sp<CameraService> service)
- : mService(service) {}
+ : mRegistered(false), mService(service) {}
void registerSelf();
void unregisterSelf();
@@ -535,11 +535,14 @@
void addOverrideUid(uid_t uid, bool active);
void removeOverrideUid(uid_t uid);
+ // IBinder::DeathRecipient implementation
+ virtual void binderDied(const wp<IBinder> &who);
private:
bool isUidActiveLocked(uid_t uid);
void updateOverrideUid(uid_t uid, bool active, bool insert);
Mutex mUidLock;
+ bool mRegistered;
wp<CameraService> mService;
std::unordered_set<uid_t> mActiveUids;
std::unordered_map<uid_t, bool> mOverrideUids;
@@ -733,7 +736,7 @@
std::vector<std::string> mNormalDeviceIds;
// sounds
- MediaPlayer* newMediaPlayer(const char *file);
+ sp<MediaPlayer> newMediaPlayer(const char *file);
Mutex mSoundLock;
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 9ab2d88..c49de8e 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1002,10 +1002,6 @@
case HAL_PIXEL_FORMAT_BLOB:
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
case HAL_PIXEL_FORMAT_YCbCr_420_888:
- case HAL_PIXEL_FORMAT_YCbCr_422_888:
- case HAL_PIXEL_FORMAT_YCbCr_444_888:
- case HAL_PIXEL_FORMAT_FLEX_RGB_888:
- case HAL_PIXEL_FORMAT_FLEX_RGBA_8888:
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index b37f004..077e05e 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -39,9 +39,6 @@
const std::string kLegacyProviderName("legacy/0");
const std::string kExternalProviderName("external/0");
-// Slash-separated list of provider types to consider for use via the old camera API
-const std::string kStandardProviderTypes("internal/legacy/external");
-
} // anonymous namespace
CameraProviderManager::HardwareServiceInteractionProxy
@@ -101,10 +98,8 @@
std::lock_guard<std::mutex> lock(mInterfaceMutex);
std::vector<std::string> deviceIds;
for (auto& provider : mProviders) {
- if (kStandardProviderTypes.find(provider->getType()) != std::string::npos) {
- for (auto& id : provider->mUniqueAPI1CompatibleCameraIds) {
- deviceIds.push_back(id);
- }
+ for (auto& id : provider->mUniqueAPI1CompatibleCameraIds) {
+ deviceIds.push_back(id);
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index e3bb5dc..f4d5a18 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -423,12 +423,20 @@
__FUNCTION__, gbp.get(), strerror(-res), res);
return res;
}
+ if ((slot < 0) || (slot > BufferQueue::NUM_BUFFER_SLOTS)) {
+ SP_LOGE("%s: Slot received %d either bigger than expected maximum %d or negative!",
+ __FUNCTION__, slot, BufferQueue::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ }
//During buffer attach 'mMutex' is not held which makes the removal of
//"gbp" possible. Check whether this is the case and continue.
if (mOutputSlots[gbp] == nullptr) {
continue;
}
auto& outputSlots = *mOutputSlots[gbp];
+ if (static_cast<size_t> (slot + 1) > outputSlots.size()) {
+ outputSlots.resize(slot + 1);
+ }
if (outputSlots[slot] != nullptr) {
// If the buffer is attached to a slot which already contains a buffer,
// the previous buffer will be removed from the output queue. Decrement
diff --git a/services/codec2/Android.bp b/services/codec2/Android.bp
deleted file mode 100644
index 4cfca1d..0000000
--- a/services/codec2/Android.bp
+++ /dev/null
@@ -1,101 +0,0 @@
-cc_binary {
- name: "vendor.google.media.c2@1.0-service",
- defaults: ["hidl_defaults"],
- soc_specific: true,
- relative_install_path: "hw",
- srcs: [
- "vendor.cpp",
- ],
-
- init_rc: ["vendor.google.media.c2@1.0-service.rc"],
-
- shared_libs: [
- "vendor.google.media.c2@1.0",
- "libavservices_minijail_vendor",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libstagefright_codec2_hidl@1.0",
- "libstagefright_codec2_vndk",
- "libutils",
- ],
-
- arch: {
- arm: {
- required: ["codec2.vendor.base.policy"],
- },
- x86: {
- required: ["codec2.vendor.base.policy"],
- },
- },
-
- compile_multilib: "32",
-}
-
-cc_binary {
- name: "vendor.google.media.c2@1.0-service-system",
- defaults: ["hidl_defaults"],
- relative_install_path: "hw",
- srcs: [
- "system.cpp",
- ],
-
- init_rc: ["vendor.google.media.c2@1.0-service-system.rc"],
-
- shared_libs: [
- "vendor.google.media.c2@1.0",
- "libavservices_minijail",
- "libcutils",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libstagefright_codec2_hidl@1.0",
- "libstagefright_codec2_vndk",
- "libutils",
- "libv4l2_c2componentstore",
- ],
-
- arch: {
- arm: {
- required: ["codec2.system.base.policy"],
- },
- x86: {
- required: ["codec2.system.base.policy"],
- },
- },
-
- required: [
- "libstagefright_soft_c2avcdec",
- "libstagefright_soft_c2avcenc",
- "libstagefright_soft_c2aacdec",
- "libstagefright_soft_c2aacenc",
- "libstagefright_soft_c2amrnbdec",
- "libstagefright_soft_c2amrnbenc",
- "libstagefright_soft_c2amrwbdec",
- "libstagefright_soft_c2amrwbenc",
- "libstagefright_soft_c2hevcdec",
- "libstagefright_soft_c2g711alawdec",
- "libstagefright_soft_c2g711mlawdec",
- "libstagefright_soft_c2mpeg2dec",
- "libstagefright_soft_c2h263dec",
- "libstagefright_soft_c2h263enc",
- "libstagefright_soft_c2mpeg4dec",
- "libstagefright_soft_c2mpeg4enc",
- "libstagefright_soft_c2mp3dec",
- "libstagefright_soft_c2vorbisdec",
- "libstagefright_soft_c2opusdec",
- "libstagefright_soft_c2vp8dec",
- "libstagefright_soft_c2vp9dec",
- "libstagefright_soft_c2vp8enc",
- "libstagefright_soft_c2vp9enc",
- "libstagefright_soft_c2rawdec",
- "libstagefright_soft_c2flacdec",
- "libstagefright_soft_c2flacenc",
- "libstagefright_soft_c2gsmdec",
- ],
-
- compile_multilib: "32",
-}
-
diff --git a/services/codec2/Android.mk b/services/codec2/Android.mk
deleted file mode 100644
index fa49875..0000000
--- a/services/codec2/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# vendor service seccomp policy
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := codec2.vendor.base.policy
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
-ifdef TARGET_2ND_ARCH
- ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_2ND_ARCH).policy
- else
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
- endif
-else
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-# system service seccomp policy
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := codec2.system.base.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
-ifdef TARGET_2ND_ARCH
- ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
- LOCAL_SRC_FILES := seccomp_policy/codec2.system.base-$(TARGET_2ND_ARCH).policy
- else
- LOCAL_SRC_FILES := seccomp_policy/codec2.system.base-$(TARGET_ARCH).policy
- endif
-else
- LOCAL_SRC_FILES := seccomp_policy/codec2.system.base-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
diff --git a/services/codec2/seccomp_policy/codec2.system.base-arm.policy b/services/codec2/seccomp_policy/codec2.system.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/services/codec2/seccomp_policy/codec2.system.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 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.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# on ARM is statically loaded at 0xffff 0000. See
-# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
-# for more details.
-mremap: arg3 == 3
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/services/codec2/seccomp_policy/codec2.system.base-x86.policy b/services/codec2/seccomp_policy/codec2.system.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/services/codec2/seccomp_policy/codec2.system.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 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.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/services/codec2/seccomp_policy/codec2.vendor.base-arm.policy b/services/codec2/seccomp_policy/codec2.vendor.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/services/codec2/seccomp_policy/codec2.vendor.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 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.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# on ARM is statically loaded at 0xffff 0000. See
-# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
-# for more details.
-mremap: arg3 == 3
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/services/codec2/seccomp_policy/codec2.vendor.base-x86.policy b/services/codec2/seccomp_policy/codec2.vendor.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/services/codec2/seccomp_policy/codec2.vendor.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 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.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/services/codec2/system.cpp b/services/codec2/system.cpp
deleted file mode 100644
index d6ec644..0000000
--- a/services/codec2/system.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2018 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 "vendor.google.media.c2@1.0-service"
-
-#include <C2PlatformSupport.h>
-#include <C2V4l2Support.h>
-#include <cutils/properties.h>
-
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <hidl/HidlTransportSupport.h>
-#include <minijail.h>
-
-// TODO: Remove this once "setenv()" call is removed.
-#include <stdlib.h>
-
-// This is created by module "codec2.system.base.policy". This can be modified.
-static constexpr char kBaseSeccompPolicyPath[] =
- "/system/etc/seccomp_policy/codec2.system.base.policy";
-
-// Additional device-specific seccomp permissions can be added in this file.
-static constexpr char kExtSeccompPolicyPath[] =
- "/system/etc/seccomp_policy/codec2.system.ext.policy";
-
-int main(int /* argc */, char** /* argv */) {
- ALOGD("vendor.google.media.c2@1.0-service-system starting...");
-
- // TODO: Remove this when all the build settings and sepolicies are in place.
- setenv("TREBLE_TESTING_OVERRIDE", "true", true);
-
- signal(SIGPIPE, SIG_IGN);
- android::SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
-
- // Extra threads may be needed to handle a stacked IPC sequence that
- // contains alternating binder and hwbinder calls. (See b/35283480.)
- android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
-
- // Create IComponentStore service.
- {
- using namespace ::vendor::google::media::c2::V1_0;
- android::sp<IComponentStore> store =
- new implementation::ComponentStore(
- android::GetCodec2PlatformComponentStore());
- if (store == nullptr) {
- ALOGE("Cannot create Codec2's IComponentStore system service.");
- } else {
- if (store->registerAsService("system") != android::OK) {
- ALOGE("Cannot register Codec2's "
- "IComponentStore system service.");
- } else {
- ALOGI("Codec2's IComponentStore system service created.");
- }
- }
-
- // To enable the v4l2 service, set this sysprop and add "v4l2" instance
- // to the system manifest file.
- if (property_get_bool("debug.stagefright.ccodec_v4l2", false)) {
- store = new implementation::ComponentStore(
- android::GetCodec2VDAComponentStore());
- if (store == nullptr) {
- ALOGE("Cannot create Codec2's IComponentStore V4L2 service.");
- } else {
- if (store->registerAsService("v4l2") != android::OK) {
- ALOGE("Cannot register Codec2's "
- "IComponentStore V4L2 service.");
- } else {
- ALOGI("Codec2's IComponentStore V4L2 service created.");
- }
- }
- }
- }
-
- android::hardware::joinRpcThreadpool();
- return 0;
-}
-
diff --git a/services/codec2/vendor.cpp b/services/codec2/vendor.cpp
deleted file mode 100644
index 60b51e2..0000000
--- a/services/codec2/vendor.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2018 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 "vendor.google.media.c2@1.0-service"
-
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <hidl/HidlTransportSupport.h>
-#include <minijail.h>
-
-#include <C2Component.h>
-
-// TODO: Remove this once "setenv()" call is removed.
-#include <stdlib.h>
-
-// This is created by module "codec2.vendor.base.policy". This can be modified.
-static constexpr char kBaseSeccompPolicyPath[] =
- "/vendor/etc/seccomp_policy/codec2.vendor.base.policy";
-
-// Additional device-specific seccomp permissions can be added in this file.
-static constexpr char kExtSeccompPolicyPath[] =
- "/vendor/etc/seccomp_policy/codec2.vendor.ext.policy";
-
-// TODO: Replace with a valid C2ComponentStore implementation.
-class DummyC2Store : public C2ComponentStore {
-public:
- DummyC2Store() = default;
-
- virtual ~DummyC2Store() override = default;
-
- virtual C2String getName() const override {
- return "default";
- }
-
- virtual c2_status_t createComponent(
- C2String /*name*/,
- std::shared_ptr<C2Component>* const /*component*/) override {
- return C2_NOT_FOUND;
- }
-
- virtual c2_status_t createInterface(
- C2String /* name */,
- std::shared_ptr<C2ComponentInterface>* const /* interface */) override {
- return C2_NOT_FOUND;
- }
-
- virtual std::vector<std::shared_ptr<const C2Component::Traits>>
- listComponents() override {
- return {};
- }
-
- virtual c2_status_t copyBuffer(
- std::shared_ptr<C2GraphicBuffer> /* src */,
- std::shared_ptr<C2GraphicBuffer> /* dst */) override {
- return C2_OMITTED;
- }
-
- virtual c2_status_t query_sm(
- const std::vector<C2Param*>& /* stackParams */,
- const std::vector<C2Param::Index>& /* heapParamIndices */,
- std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const override {
- return C2_OMITTED;
- }
-
- virtual c2_status_t config_sm(
- const std::vector<C2Param*>& /* params */,
- std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) override {
- return C2_OMITTED;
- }
-
- virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override {
- return nullptr;
- }
-
- virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const override {
- return C2_OMITTED;
- }
-
- virtual c2_status_t querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery>& /* fields */) const override {
- return C2_OMITTED;
- }
-};
-
-int main(int /* argc */, char** /* argv */) {
- ALOGD("vendor.google.media.c2@1.0-service starting...");
-
- // TODO: Remove this when all the build settings and sepolicies are in place.
- setenv("TREBLE_TESTING_OVERRIDE", "true", true);
-
- signal(SIGPIPE, SIG_IGN);
- android::SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
-
- // Extra threads may be needed to handle a stacked IPC sequence that
- // contains alternating binder and hwbinder calls. (See b/35283480.)
- android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
-
- // Create IComponentStore service.
- {
- using namespace ::vendor::google::media::c2::V1_0;
- android::sp<IComponentStore> store =
- new implementation::ComponentStore(
- // TODO: Replace this with a valid C2ComponentStore
- // implementation.
- std::make_shared<DummyC2Store>());
- if (store == nullptr) {
- ALOGE("Cannot create Codec2's IComponentStore service.");
- } else {
- if (store->registerAsService("default") != android::OK) {
- ALOGE("Cannot register Codec2's "
- "IComponentStore service.");
- } else {
- ALOGI("Codec2's IComponentStore service created.");
- }
- }
- }
-
- android::hardware::joinRpcThreadpool();
- return 0;
-}
-
diff --git a/services/codec2/vendor.google.media.c2@1.0-service-system.rc b/services/codec2/vendor.google.media.c2@1.0-service-system.rc
deleted file mode 100644
index 0577a1d..0000000
--- a/services/codec2/vendor.google.media.c2@1.0-service-system.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor-google-media-c2-system-hal-1-0 /system/bin/hw/vendor.google.media.c2@1.0-service-system
- class hal
- user media
- group mediadrm drmrpc
- ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
-
diff --git a/services/codec2/vendor.google.media.c2@1.0-service.rc b/services/codec2/vendor.google.media.c2@1.0-service.rc
deleted file mode 100644
index 3e7e0a6..0000000
--- a/services/codec2/vendor.google.media.c2@1.0-service.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor-google-media-c2-hal-1-0 /vendor/bin/hw/vendor.google.media.c2@1.0-service
- class hal
- user media
- group mediadrm drmrpc
- ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
-
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 1553ec7..bbbe552 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -16,12 +16,14 @@
mprotect: 1
prctl: 1
openat: 1
+open: 1
getuid32: 1
writev: 1
ioctl: 1
close: 1
mmap2: 1
fstat64: 1
+stat64: 1
madvise: 1
fstatat64: 1
futex: 1
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 7b8d817..11fd9f6 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -201,14 +201,14 @@
if (endpoint.get() != nullptr) {
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("openSharedEndpoint(), open failed");
+ ALOGE("%s(), open failed", __func__);
endpoint.clear();
} else {
mSharedStreams.push_back(endpoint);
}
}
- ALOGD("openSharedEndpoint(), created %p, requested device = %d, dir = %d",
- endpoint.get(), configuration.getDeviceId(), (int)direction);
+ ALOGD("%s(), created endpoint %p, requested device = %d, dir = %d",
+ __func__, endpoint.get(), configuration.getDeviceId(), (int)direction);
IPCThreadState::self()->restoreCallingIdentity(token);
}
@@ -244,8 +244,8 @@
mExclusiveStreams.end());
serviceEndpoint->close();
- ALOGD("closeExclusiveEndpoint() %p for device %d",
- serviceEndpoint.get(), serviceEndpoint->getDeviceId());
+ ALOGD("%s() %p for device %d",
+ __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
@@ -266,7 +266,7 @@
mSharedStreams.end());
serviceEndpoint->close();
- ALOGD("closeSharedEndpoint() %p for device %d",
- serviceEndpoint.get(), serviceEndpoint->getDeviceId());
+ ALOGD("%s() %p for device %d",
+ __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index c708fee..ad5bb3a 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -165,7 +165,6 @@
}
aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
- ALOGD("closeStream(0x%08X)", streamHandle);
// Check permission and ownership first.
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 33439fc..96e621a 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -39,7 +39,7 @@
using namespace aaudio; // TODO just import names needed
AAudioServiceEndpoint::~AAudioServiceEndpoint() {
- ALOGD("AAudioServiceEndpoint::~AAudioServiceEndpoint() destroying endpoint %p", this);
+ ALOGD("%s(%p) destroyed", __func__, this);
}
std::string AAudioServiceEndpoint::dump() const {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index db01c88..52990da 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -98,8 +98,8 @@
.flags = AUDIO_FLAG_LOW_LATENCY,
.tags = ""
};
- ALOGV("open() MMAP attributes.usage = %d, content_type = %d, source = %d",
- attributes.usage, attributes.content_type, attributes.source);
+ ALOGD("%s(%p) MMAP attributes.usage = %d, content_type = %d, source = %d",
+ __func__, this, attributes.usage, attributes.content_type, attributes.source);
mMmapClient.clientUid = request.getUserId();
mMmapClient.clientPid = request.getProcessId();
@@ -135,7 +135,7 @@
mHardwareTimeOffsetNanos = INPUT_ESTIMATED_HARDWARE_OFFSET_NANOS; // frames at ADC earlier
} else {
- ALOGE("openMmapStream - invalid direction = %d", direction);
+ ALOGE("%s() invalid direction = %d", __func__, direction);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
@@ -157,20 +157,20 @@
this, // callback
mMmapStream,
&mPortHandle);
- ALOGD("open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
- mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
+ ALOGD("%s() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+ __func__, mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
if (status != OK) {
- ALOGE("openMmapStream returned status %d", status);
+ ALOGE("%s() openMmapStream() returned status %d", __func__, status);
return AAUDIO_ERROR_UNAVAILABLE;
}
if (deviceId == AAUDIO_UNSPECIFIED) {
- ALOGW("open() - openMmapStream() failed to set deviceId");
+ ALOGW("%s() openMmapStream() failed to set deviceId", __func__);
}
setDeviceId(deviceId);
if (sessionId == AUDIO_SESSION_ALLOCATE) {
- ALOGW("open() - openMmapStream() failed to set sessionId");
+ ALOGW("%s() - openMmapStream() failed to set sessionId", __func__);
}
aaudio_session_id_t actualSessionId =
@@ -178,7 +178,7 @@
? AAUDIO_SESSION_ID_NONE
: (aaudio_session_id_t) sessionId;
setSessionId(actualSessionId);
- ALOGD("open() deviceId = %d, sessionId = %d", getDeviceId(), getSessionId());
+ ALOGD("%s() deviceId = %d, sessionId = %d", __func__, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
int32_t minSizeFrames = getBufferCapacity();
@@ -187,14 +187,14 @@
}
status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
if (status != OK) {
- ALOGE("open() - createMmapBuffer() failed with status %d %s",
- status, strerror(-status));
+ ALOGE("%s() - createMmapBuffer() failed with status %d %s",
+ __func__, status, strerror(-status));
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
} else {
- ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d"
+ ALOGD("%s() createMmapBuffer() returned = %d, buffer_size = %d, burst_size %d"
", Sharable FD: %s",
- status,
+ __func__, status,
abs(mMmapBufferinfo.buffer_size_frames),
mMmapBufferinfo.burst_size_frames,
mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
@@ -214,7 +214,7 @@
// Fallback is handled by caller but indicate what is possible in case
// this is used in the future
setSharingMode(AAUDIO_SHARING_MODE_SHARED);
- ALOGW("open() - exclusive FD cannot be used by client");
+ ALOGW("%s() - exclusive FD cannot be used by client", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -229,7 +229,7 @@
// Assume that AudioFlinger will close the original shared_memory_fd.
mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
if (mAudioDataFileDescriptor.get() == -1) {
- ALOGE("open() - could not dup shared_memory_fd");
+ ALOGE("%s() - could not dup shared_memory_fd", __func__);
result = AAUDIO_ERROR_INTERNAL;
goto error;
}
@@ -247,12 +247,12 @@
burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
} while (burstMicros < burstMinMicros);
- ALOGD("open() original burst = %d, minMicros = %d, to burst = %d\n",
- mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
+ ALOGD("%s() original burst = %d, minMicros = %d, to burst = %d\n",
+ __func__, mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
- ALOGD("open() actual rate = %d, channels = %d"
+ ALOGD("%s() actual rate = %d, channels = %d"
", deviceId = %d, capacity = %d\n",
- getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
+ __func__, getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
return result;
@@ -262,9 +262,8 @@
}
aaudio_result_t AAudioServiceEndpointMMAP::close() {
-
if (mMmapStream != 0) {
- ALOGD("close() clear() endpoint");
+ ALOGD("%s() clear() endpoint", __func__);
// Needs to be explicitly cleared or CTS will fail but it is not clear why.
mMmapStream.clear();
// Apparently the above close is asynchronous. An attempt to open a new device
@@ -299,20 +298,18 @@
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- ALOGD("startClient(%p(uid=%d, pid=%d))",
- &client, client.clientUid, client.clientPid);
+ ALOGV("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
audio_port_handle_t originalHandle = *clientHandle;
status_t status = mMmapStream->start(client, clientHandle);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- ALOGD("startClient() , %d => %d returns %d",
- originalHandle, *clientHandle, result);
+ ALOGV("%s() , %d => %d returns %d", __func__, originalHandle, *clientHandle, result);
return result;
}
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- ALOGD("stopClient(%d) returns %d", clientHandle, result);
+ ALOGV("%s(%d) returns %d", __func__, clientHandle, result);
return result;
}
@@ -324,13 +321,13 @@
return AAUDIO_ERROR_NULL;
}
status_t status = mMmapStream->getMmapPosition(&position);
- ALOGV("getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
- status, position.position_frames, (long long) position.time_nanoseconds);
+ ALOGV("%s() status= %d, pos = %d, nanos = %lld\n",
+ __func__, status, position.position_frames, (long long) position.time_nanoseconds);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
if (result == AAUDIO_ERROR_UNAVAILABLE) {
- ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data available");
+ ALOGW("%s(): getMmapPosition() has no position data available", __func__);
} else if (result != AAUDIO_OK) {
- ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
+ ALOGE("%s(): getMmapPosition() returned status %d", __func__, status);
} else {
// Convert 32-bit position to 64-bit position.
mFramesTransferred.update32(position.position_frames);
@@ -347,15 +344,16 @@
void AAudioServiceEndpointMMAP::onTearDown() {
- ALOGD("onTearDown() called");
+ ALOGD("%s(%p) called", __func__, this);
disconnectRegisteredStreams();
};
void AAudioServiceEndpointMMAP::onVolumeChanged(audio_channel_mask_t channels,
android::Vector<float> values) {
- // TODO do we really need a different volume for each channel?
+ // TODO Do we really need a different volume for each channel?
+ // We get called with an array filled with a single value!
float volume = values[0];
- ALOGD("onVolumeChanged() volume[0] = %f", volume);
+ ALOGD("%s(%p) volume[0] = %f", __func__, this, volume);
std::lock_guard<std::mutex> lock(mLockStreams);
for(const auto stream : mRegisteredStreams) {
stream->onVolumeChanged(volume);
@@ -363,8 +361,7 @@
};
void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
- ALOGD("onRoutingChanged() called with dev %d, old = %d",
- deviceId, getDeviceId());
+ ALOGD("%s(%p) called with dev %d, old = %d", __func__, this, deviceId, getDeviceId());
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
disconnectRegisteredStreams();
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 2601f3f..a274466 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -43,10 +43,12 @@
AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
: mStreamInternalPlay(audioService, true) {
+ ALOGD("%s(%p) created", __func__, this);
mStreamInternal = &mStreamInternalPlay;
}
AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() {
+ ALOGD("%s(%p) destroyed", __func__, this);
}
aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) {
@@ -68,6 +70,7 @@
// Mix data from each application stream and write result to the shared MMAP stream.
void *AAudioServiceEndpointPlay::callbackLoop() {
+ ALOGD("%s() entering >>>>>>>>>>>>>>> MIXER", __func__);
aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -152,5 +155,7 @@
}
}
+ ALOGD("%s() exiting, enabled = %d, state = %d, result = %d <<<<<<<<<<<<< MIXER",
+ __func__, mCallbackEnabled.load(), getStreamInternal()->getState(), result);
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 584efe5..f08a52f 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -89,18 +89,22 @@
}
// Glue between C and C++ callbacks.
-static void *aaudio_endpoint_thread_proc(void *context) {
- AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
- if (endpoint != NULL) {
- void *result = endpoint->callbackLoop();
- // Close now so that the HW resource is freed and we can open a new device.
- if (!endpoint->isConnected()) {
- endpoint->close();
- }
- return result;
- } else {
- return NULL;
+static void *aaudio_endpoint_thread_proc(void *arg) {
+ assert(arg != nullptr);
+
+ // The caller passed in a smart pointer to prevent the endpoint from getting deleted
+ // while the thread was launching.
+ sp<AAudioServiceEndpointShared> *endpointForThread =
+ static_cast<sp<AAudioServiceEndpointShared> *>(arg);
+ sp<AAudioServiceEndpointShared> endpoint = *endpointForThread;
+ delete endpointForThread; // Just use scoped smart pointer. Don't need this anymore.
+ void *result = endpoint->callbackLoop();
+ // Close now so that the HW resource is freed and we can open a new device.
+ if (!endpoint->isConnected()) {
+ endpoint->close();
}
+
+ return result;
}
aaudio_result_t aaudio::AAudioServiceEndpointShared::startSharingThread_l() {
@@ -109,7 +113,16 @@
* AAUDIO_NANOS_PER_SECOND
/ getSampleRate();
mCallbackEnabled.store(true);
- return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
+ // Pass a smart pointer so the thread can hold a reference.
+ sp<AAudioServiceEndpointShared> *endpointForThread = new sp<AAudioServiceEndpointShared>(this);
+ aaudio_result_t result = getStreamInternal()->createThread(periodNanos,
+ aaudio_endpoint_thread_proc,
+ endpointForThread);
+ if (result != AAUDIO_OK) {
+ // The thread can't delete it so we have to do it here.
+ delete endpointForThread;
+ }
+ return result;
}
aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() {
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 74cd817..227250c 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -54,12 +54,13 @@
virtual void *callbackLoop() = 0;
+
+protected:
+
AudioStreamInternal *getStreamInternal() const {
return mStreamInternal;
};
-protected:
-
aaudio_result_t startSharingThread_l();
aaudio_result_t stopSharingThread();
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index e8c9e41..18f14ee 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -93,7 +93,7 @@
{
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue != nullptr) {
- ALOGE("open() called twice");
+ ALOGE("%s() called twice", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -108,7 +108,7 @@
request,
sharingMode);
if (mServiceEndpoint == nullptr) {
- ALOGE("open() openEndpoint() failed");
+ ALOGE("%s() openEndpoint() failed", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -167,7 +167,7 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("start() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
result = AAUDIO_ERROR_INVALID_STATE;
goto error;
}
@@ -201,7 +201,7 @@
return result;
}
if (mServiceEndpoint == nullptr) {
- ALOGE("pause() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -217,7 +217,7 @@
result = mServiceEndpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("pause() mServiceEndpoint returned %d", result);
+ ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
disconnect(); // TODO should we return or pause Base first?
}
@@ -233,7 +233,7 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("stop() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -251,7 +251,7 @@
// TODO wait for data to be played out
result = mServiceEndpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("stop() mServiceEndpoint returned %d", result);
+ ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
disconnect();
// TODO what to do with result here?
}
@@ -284,7 +284,7 @@
// implement Runnable, periodically send timestamps to client
void AAudioServiceStreamBase::run() {
- ALOGD("run() entering ----------------");
+ ALOGD("%s() %s entering >>>>>>>>>>>>>> TIMESTAMPS", __func__, getTypeText());
TimestampScheduler timestampScheduler;
timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
@@ -302,7 +302,7 @@
AudioClock::sleepUntilNanoTime(nextTime);
}
}
- ALOGD("run() exiting ----------------");
+ ALOGD("%s() %s exiting <<<<<<<<<<<<<< TIMESTAMPS", __func__, getTypeText());
}
void AAudioServiceStreamBase::disconnect() {
@@ -333,12 +333,12 @@
aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue == nullptr) {
- ALOGE("writeUpMessageQueue(): mUpMessageQueue null! - stream not open");
+ ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
if (count != 1) {
- ALOGE("writeUpMessageQueue(): Queue full. Did client die?");
+ ALOGE("%s(): Queue full. Did client die? %s", __func__, getTypeText());
return AAUDIO_ERROR_WOULD_BLOCK;
} else {
return AAUDIO_OK;
@@ -355,7 +355,7 @@
aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
&command.timestamp.timestamp);
if (result == AAUDIO_OK) {
- ALOGV("sendCurrentTimestamp() SERVICE %8lld at %lld",
+ ALOGV("%s() SERVICE %8lld at %lld", __func__,
(long long) command.timestamp.position,
(long long) command.timestamp.timestamp);
command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
@@ -366,7 +366,7 @@
result = getHardwareTimestamp(&command.timestamp.position,
&command.timestamp.timestamp);
if (result == AAUDIO_OK) {
- ALOGV("sendCurrentTimestamp() HARDWARE %8lld at %lld",
+ ALOGV("%s() HARDWARE %8lld at %lld", __func__,
(long long) command.timestamp.position,
(long long) command.timestamp.timestamp);
command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
@@ -389,7 +389,7 @@
{
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue == nullptr) {
- ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+ ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
// Gather information on the message queue.
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 5f5bb98..3720596 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -55,7 +55,7 @@
, public Runnable {
public:
- AAudioServiceStreamBase(android::AAudioService &aAudioService);
+ explicit AAudioServiceStreamBase(android::AAudioService &aAudioService);
virtual ~AAudioServiceStreamBase();
@@ -219,6 +219,8 @@
mCloseNeeded.store(needed);
}
+ virtual const char *getTypeText() const { return "Base"; }
+
protected:
/**
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index e2415d0..1509f7d 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -69,9 +69,7 @@
aaudio_result_t close() override;
- /**
- * Send a MMAP/NOIRQ buffer timestamp to the client.
- */
+ const char *getTypeText() const override { return "MMAP"; }
protected:
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 3b12e61..61769b5 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -43,7 +43,7 @@
class AAudioServiceStreamShared : public AAudioServiceStreamBase {
public:
- AAudioServiceStreamShared(android::AAudioService &aAudioService);
+ explicit AAudioServiceStreamShared(android::AAudioService &aAudioService);
virtual ~AAudioServiceStreamShared() = default;
static std::string dumpHeader();
@@ -87,6 +87,8 @@
return mXRunCount.load();
}
+ const char *getTypeText() const override { return "Shared"; }
+
protected:
aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index ffc9b7b..dcce68a 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -44,7 +44,7 @@
public:
AAudioThread();
- AAudioThread(const char *prefix);
+ explicit AAudioThread(const char *prefix);
virtual ~AAudioThread() = default;