Merge "OMX: Ensure nStride, if very negative, does not cause an overflow"
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..838dd4a 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,42 @@
srcs: ["include/camera/**/*.h"],
license: "NOTICE",
}
+
+cc_library_shared {
+ name: "libcamera2",
+ srcs: [
+ "NdkCameraManager.cpp",
+ "NdkCameraMetadata.cpp",
+ "NdkCameraDevice.cpp",
+ "NdkCaptureRequest.cpp",
+ "NdkCameraCaptureSession.cpp",
+ "impl/ACameraManager.cpp",
+ "impl/ACameraMetadata.cpp",
+ "impl/ACameraDevice.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libgui",
+ "libutils",
+ "libandroid_runtime",
+ "libcamera_client",
+ "libstagefright_foundation",
+ "libcutils",
+ "libcamera_metadata",
+ "libmediandk",
+ "libnativewindow",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-DEXPORT=__attribute__ ((visibility (\"default\")))",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libnativewindow",
+ ]
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index f5ff69d..a5aab07 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -14,6 +14,8 @@
# limitations under the License.
#
+# TODO(b/118434782): Remove this file and change name of the libcamera2
+# module in the existing Android.bp file to libcamera2ndk.
LOCAL_PATH:= $(call my-dir)
ifneq ($(TARGET_BUILD_PDK), true)
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c908323..ac3be25 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1290,16 +1290,21 @@
}
default:
ALOGE("Unknown error from camera device: %d", errorCode);
- // no break
+ [[fallthrough]];
case ERROR_CAMERA_DEVICE:
case ERROR_CAMERA_SERVICE:
{
+ int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+ // We keep this switch since this block might be encountered with
+ // more than just 2 states. The default fallthrough could have us
+ // handling more unmatched error cases.
switch (errorCode) {
case ERROR_CAMERA_DEVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
break;
case ERROR_CAMERA_SERVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ errorVal = ::ERROR_CAMERA_SERVICE;
break;
default:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1314,7 @@
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
- msg->setInt32(kErrorCodeKey, errorCode);
+ msg->setInt32(kErrorCodeKey, errorVal);
msg->post();
break;
}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 6ebd850..8af3c7c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -6327,7 +6327,7 @@
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
*/
ACAMERA_CONTROL_SCENE_MODE_CANDLELIGHT = 15,
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 1b8e8d9..7d3fbea 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -58,7 +58,36 @@
#include "Overlay.h"
#include "FrameOutput.h"
-using namespace android;
+using android::ABuffer;
+using android::ALooper;
+using android::AMessage;
+using android::AString;
+using android::DisplayInfo;
+using android::FrameOutput;
+using android::IBinder;
+using android::IGraphicBufferProducer;
+using android::ISurfaceComposer;
+using android::MediaCodec;
+using android::MediaCodecBuffer;
+using android::MediaMuxer;
+using android::Overlay;
+using android::PersistentSurface;
+using android::ProcessState;
+using android::Rect;
+using android::String8;
+using android::SurfaceComposerClient;
+using android::Vector;
+using android::sp;
+using android::status_t;
+
+using android::DISPLAY_ORIENTATION_0;
+using android::DISPLAY_ORIENTATION_180;
+using android::DISPLAY_ORIENTATION_90;
+using android::INFO_FORMAT_CHANGED;
+using android::INFO_OUTPUT_BUFFERS_CHANGED;
+using android::INVALID_OPERATION;
+using android::NO_ERROR;
+using android::UNKNOWN_ERROR;
static const uint32_t kMinBitRate = 100000; // 0.1Mbps
static const uint32_t kMaxBitRate = 200 * 1000000; // 200Mbps
diff --git a/drm/mediadrm/plugins/clearkey/common/Utils.cpp b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
index 93c643b..d48b0a8 100644
--- a/drm/mediadrm/plugins/clearkey/common/Utils.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
@@ -27,4 +27,18 @@
return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
}
+std::string ByteArrayToHexString(const uint8_t* in_buffer, size_t length) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters.
+ std::string out_buffer(length * 2, '\0');
+
+ for (size_t i = 0; i < length; ++i) {
+ char byte = in_buffer[i];
+ out_buffer[(i * 2)] = kHexChars[(byte >> 4) & 0xf];
+ out_buffer[(i * 2) + 1] = kHexChars[byte & 0xf];
+ }
+ return out_buffer;
+}
+
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/common/include/Utils.h b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
index 2543124..aa571c0 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/Utils.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
@@ -17,14 +17,16 @@
#ifndef CLEARKEY_UTILS_H_
#define CLEARKEY_UTILS_H_
+#include <string>
#include <utils/Vector.h>
+namespace android {
// Add a comparison operator for this Vector specialization so that it can be
// used as a key in a KeyedVector.
-namespace android {
-
bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs);
+std::string ByteArrayToHexString(const uint8_t* in_buffer, size_t length);
+
} // namespace android
#define UNUSED(x) (void)(x);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index 341d4f6..edf818e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -25,10 +25,12 @@
"CreatePluginFactories.cpp",
"CryptoFactory.cpp",
"CryptoPlugin.cpp",
+ "DeviceFiles.cpp",
"DrmFactory.cpp",
"DrmPlugin.cpp",
"InitDataParser.cpp",
"JsonWebKey.cpp",
+ "MemoryFileSystem.cpp",
"Session.cpp",
"SessionLibrary.cpp",
"service.cpp",
@@ -49,11 +51,13 @@
"libhidlmemory",
"libhidltransport",
"liblog",
+ "libprotobuf-cpp-lite",
"libutils",
],
static_libs: [
"libclearkeycommon",
+ "libclearkeydevicefiles-protos",
"libjsmn",
],
@@ -66,3 +70,13 @@
},
}
+cc_library_static {
+ name: "libclearkeydevicefiles-protos",
+ vendor: true,
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: ["protos/DeviceFiles.proto"],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
new file mode 100644
index 0000000..8fafce2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
@@ -0,0 +1,240 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+
+#include <utils/Log.h>
+
+#include <string>
+#include <sys/stat.h>
+
+#include "DeviceFiles.h"
+#include "Utils.h"
+
+#include <openssl/sha.h>
+
+// Protobuf generated classes.
+using android::hardware::drm::V1_1::clearkey::OfflineFile;
+using android::hardware::drm::V1_1::clearkey::HashedFile;
+using android::hardware::drm::V1_1::clearkey::License;
+using android::hardware::drm::V1_1::clearkey::License_LicenseState_ACTIVE;
+using android::hardware::drm::V1_1::clearkey::License_LicenseState_RELEASING;
+
+namespace {
+const char kLicenseFileNameExt[] = ".lic";
+
+bool Hash(const std::string& data, std::string* hash) {
+ if (!hash) return false;
+
+ hash->resize(SHA256_DIGEST_LENGTH);
+
+ const unsigned char* input = reinterpret_cast<const unsigned char*>(data.data());
+ unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
+ SHA256(input, data.size(), output);
+ return true;
+}
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+bool DeviceFiles::StoreLicense(
+ const std::string& keySetId, LicenseState state,
+ const std::string& licenseResponse) {
+
+ OfflineFile file;
+ file.set_type(OfflineFile::LICENSE);
+ file.set_version(OfflineFile::VERSION_1);
+
+ License* license = file.mutable_license();
+ switch (state) {
+ case kLicenseStateActive:
+ license->set_state(License_LicenseState_ACTIVE);
+ license->set_license(licenseResponse);
+ break;
+ case kLicenseStateReleasing:
+ license->set_state(License_LicenseState_RELEASING);
+ break;
+ default:
+ ALOGW("StoreLicense: Unknown license state: %u", state);
+ return false;
+ }
+
+ std::string serializedFile;
+ file.SerializeToString(&serializedFile);
+
+ return StoreFileWithHash(keySetId + kLicenseFileNameExt, serializedFile);
+}
+
+bool DeviceFiles::StoreFileWithHash(const std::string& fileName,
+ const std::string& serializedFile) {
+ std::string hash;
+ if (!Hash(serializedFile, &hash)) {
+ ALOGE("StoreFileWithHash: Failed to compute hash");
+ return false;
+ }
+
+ HashedFile hashFile;
+ hashFile.set_file(serializedFile);
+ hashFile.set_hash(hash);
+
+ std::string serializedHashFile;
+ hashFile.SerializeToString(&serializedHashFile);
+
+ return StoreFileRaw(fileName, serializedHashFile);
+}
+
+bool DeviceFiles::StoreFileRaw(const std::string& fileName, const std::string& serializedHashFile) {
+ MemoryFileSystem::MemoryFile memFile;
+ memFile.setFileName(fileName);
+ memFile.setContent(serializedHashFile);
+ memFile.setFileSize(serializedHashFile.size());
+ size_t len = mFileHandle.Write(fileName, memFile);
+
+ if (len != static_cast<size_t>(serializedHashFile.size())) {
+ ALOGE("StoreFileRaw: Failed to write %s", fileName.c_str());
+ ALOGD("StoreFileRaw: expected=%zd, actual=%zu", serializedHashFile.size(), len);
+ return false;
+ }
+
+ ALOGD("StoreFileRaw: wrote %zu bytes to %s", serializedHashFile.size(), fileName.c_str());
+ return true;
+}
+
+bool DeviceFiles::RetrieveLicense(
+ const std::string& keySetId, LicenseState* state, std::string* offlineLicense) {
+ OfflineFile file;
+
+ if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
+ return false;
+ }
+
+ if (file.type() != OfflineFile::LICENSE) {
+ ALOGE("RetrieveLicense: Invalid file type");
+ return false;
+ }
+
+ if (file.version() != OfflineFile::VERSION_1) {
+ ALOGE("RetrieveLicense: Invalid file version");
+ return false;
+ }
+
+ if (!file.has_license()) {
+ ALOGE("RetrieveLicense: License not present");
+ return false;
+ }
+
+ License license = file.license();
+
+ switch (license.state()) {
+ case License_LicenseState_ACTIVE:
+ *state = kLicenseStateActive;
+ break;
+ case License_LicenseState_RELEASING:
+ *state = kLicenseStateReleasing;
+ break;
+ default:
+ ALOGW("RetrieveLicense: Unrecognized license state: %u",
+ kLicenseStateUnknown);
+ *state = kLicenseStateUnknown;
+ break;
+ }
+
+ *offlineLicense = license.license();
+ return true;
+}
+
+bool DeviceFiles::DeleteAllLicenses() {
+ return mFileHandle.RemoveAllFiles();
+}
+
+bool DeviceFiles::LicenseExists(const std::string& keySetId) {
+ return mFileHandle.FileExists(keySetId + kLicenseFileNameExt);
+}
+
+bool DeviceFiles::RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile) {
+ if (!deSerializedFile) {
+ ALOGE("RetrieveHashedFile: invalid file parameter");
+ return false;
+ }
+
+ if (!FileExists(fileName)) {
+ ALOGE("RetrieveHashedFile: %s does not exist", fileName.c_str());
+ return false;
+ }
+
+ ssize_t bytes = GetFileSize(fileName);
+ if (bytes <= 0) {
+ ALOGE("RetrieveHashedFile: invalid file size: %s", fileName.c_str());
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string serializedHashFile;
+ serializedHashFile.resize(bytes);
+ bytes = mFileHandle.Read(fileName, &serializedHashFile);
+
+ if (bytes != static_cast<ssize_t>(serializedHashFile.size())) {
+ ALOGE("RetrieveHashedFile: Failed to read from %s", fileName.c_str());
+ ALOGV("RetrieveHashedFile: expected: %zd, actual: %zd", serializedHashFile.size(), bytes);
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ ALOGV("RetrieveHashedFile: read %zd from %s", bytes, fileName.c_str());
+
+ HashedFile hashFile;
+ if (!hashFile.ParseFromString(serializedHashFile)) {
+ ALOGE("RetrieveHashedFile: Unable to parse hash file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string hash;
+ if (!Hash(hashFile.file(), &hash)) {
+ ALOGE("RetrieveHashedFile: Hash computation failed");
+ return false;
+ }
+
+ if (hash != hashFile.hash()) {
+ ALOGE("RetrieveHashedFile: Hash mismatch");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ if (!deSerializedFile->ParseFromString(hashFile.file())) {
+ ALOGE("RetrieveHashedFile: Unable to parse file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ return true;
+}
+
+bool DeviceFiles::FileExists(const std::string& fileName) const {
+ return mFileHandle.FileExists(fileName);
+}
+
+bool DeviceFiles::RemoveFile(const std::string& fileName) {
+ return mFileHandle.RemoveFile(fileName);
+}
+
+ssize_t DeviceFiles::GetFileSize(const std::string& fileName) const {
+ return mFileHandle.GetFileSize(fileName);
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 3b61085..59dfb89 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -25,11 +25,15 @@
#include "ClearKeyDrmProperties.h"
#include "Session.h"
#include "TypeConvert.h"
+#include "Utils.h"
namespace {
+const std::string kKeySetIdPrefix("ckid");
+const int kKeySetIdLength = 16;
const int kSecureStopIdStart = 100;
+const std::string kOfflineLicense("\"type\":\"persistent-license\"");
const std::string kStreaming("Streaming");
-const std::string kOffline("Offline");
+const std::string kTemporaryLicense("\"type\":\"temporary\"");
const std::string kTrue("True");
const std::string kQueryKeyLicenseType("LicenseType");
@@ -66,6 +70,7 @@
mPlayPolicy.clear();
initProperties();
mSecureStops.clear();
+ std::srand(std::time(nullptr));
}
void DrmPlugin::initProperties() {
@@ -147,25 +152,53 @@
std::string *defaultUrl) {
UNUSED(optionalParameters);
+ // GetKeyRequestOfflineKeyTypeNotSupported() in vts 1.0 and 1.1 expects
+ // KeyType::OFFLINE to return ERROR_DRM_CANNOT_HANDLE in clearkey plugin.
+ // Those tests pass in an empty initData, we use the empty initData to
+ // signal the specific use case.
+ if (keyType == KeyType::OFFLINE && 0 == initData.size()) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
*defaultUrl = "";
*keyRequestType = KeyRequestType::UNKNOWN;
*request = std::vector<uint8_t>();
- if (scope.size() == 0) {
+ if (scope.size() == 0 ||
+ (keyType != KeyType::STREAMING &&
+ keyType != KeyType::OFFLINE &&
+ keyType != KeyType::RELEASE)) {
return Status::BAD_VALUE;
}
- if (keyType != KeyType::STREAMING) {
- return Status::ERROR_DRM_CANNOT_HANDLE;
+ const std::vector<uint8_t> scopeId = toVector(scope);
+ sp<Session> session;
+ if (keyType == KeyType::STREAMING || keyType == KeyType::OFFLINE) {
+ std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
+ session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+ *keyRequestType = KeyRequestType::INITIAL;
}
- sp<Session> session = mSessionLibrary->findSession(toVector(scope));
- if (!session.get()) {
- return Status::ERROR_DRM_SESSION_NOT_OPENED;
- }
+ Status status = session->getKeyRequest(initData, mimeType, keyType, request);
- Status status = session->getKeyRequest(initData, mimeType, request);
- *keyRequestType = KeyRequestType::INITIAL;
+ if (keyType == KeyType::RELEASE) {
+ std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
+ std::string requestString(request->begin(), request->end());
+ if (requestString.find(kOfflineLicense) != std::string::npos) {
+ std::string emptyResponse;
+ std::string keySetIdString(keySetId.begin(), keySetId.end());
+ if (!mFileHandle.StoreLicense(keySetIdString,
+ DeviceFiles::kLicenseStateReleasing,
+ emptyResponse)) {
+ ALOGE("Problem releasing offline license");
+ return Status::ERROR_DRM_UNKNOWN;
+ }
+ }
+ *keyRequestType = KeyRequestType::RELEASE;
+ }
return status;
}
@@ -227,6 +260,30 @@
mPlayPolicy.push_back(policy);
}
+bool DrmPlugin::makeKeySetId(std::string* keySetId) {
+ if (!keySetId) {
+ ALOGE("keySetId destination not provided");
+ return false;
+ }
+ std::vector<uint8_t> ksid(kKeySetIdPrefix.begin(), kKeySetIdPrefix.end());
+ ksid.resize(kKeySetIdLength);
+ std::vector<uint8_t> randomData((kKeySetIdLength - kKeySetIdPrefix.size()) / 2, 0);
+
+ while (keySetId->empty()) {
+ for (auto itr = randomData.begin(); itr != randomData.end(); ++itr) {
+ *itr = std::rand() % 0xff;
+ }
+ *keySetId = kKeySetIdPrefix + ByteArrayToHexString(
+ reinterpret_cast<const uint8_t*>(randomData.data()), randomData.size());
+ if (mFileHandle.LicenseExists(*keySetId)) {
+ // collision, regenerate
+ ALOGV("Retry generating KeySetId");
+ keySetId->clear();
+ }
+ }
+ return true;
+}
+
Return<void> DrmPlugin::provideKeyResponse(
const hidl_vec<uint8_t>& scope,
const hidl_vec<uint8_t>& response,
@@ -237,46 +294,109 @@
return Void();
}
- sp<Session> session = mSessionLibrary->findSession(toVector(scope));
- if (!session.get()) {
- _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
- return Void();
- }
+ std::string responseString(
+ reinterpret_cast<const char*>(response.data()), response.size());
+ const std::vector<uint8_t> scopeId = toVector(scope);
+ std::vector<uint8_t> sessionId;
+ std::string keySetId;
- setPlayPolicy();
- std::vector<uint8_t> keySetId;
- keySetId.clear();
+ Status status = Status::OK;
+ bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
+ bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
+ if (isRelease) {
+ keySetId.assign(scopeId.begin(), scopeId.end());
+ } else {
+ sessionId.assign(scopeId.begin(), scopeId.end());
+ sp<Session> session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
+ return Void();
+ }
- Status status = session->provideKeyResponse(response);
- if (status == Status::OK) {
- // Test calling AMediaDrm listeners.
- sendEvent(EventType::VENDOR_DEFINED, toVector(scope), toVector(scope));
+ setPlayPolicy();
+ // non offline license returns empty keySetId
+ keySetId.clear();
- sendExpirationUpdate(toVector(scope), 100);
+ status = session->provideKeyResponse(response);
+ if (status == Status::OK) {
+ if (isOfflineLicense) {
+ if (!makeKeySetId(&keySetId)) {
+ _hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec<uint8_t>());
+ return Void();
+ }
+ bool ok = mFileHandle.StoreLicense(
+ keySetId,
+ DeviceFiles::kLicenseStateActive,
+ std::string(response.begin(), response.end()));
+ if (!ok) {
+ ALOGE("Failed to store offline license");
+ }
+ }
- std::vector<KeyStatus> keysStatus;
- KeyStatus keyStatus;
+ // Test calling AMediaDrm listeners.
+ sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
- std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
- keyStatus.keyId = keyId1;
- keyStatus.type = V1_0::KeyStatusType::USABLE;
- keysStatus.push_back(keyStatus);
+ sendExpirationUpdate(sessionId, 100);
- std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
- keyStatus.keyId = keyId2;
- keyStatus.type = V1_0::KeyStatusType::EXPIRED;
- keysStatus.push_back(keyStatus);
+ std::vector<KeyStatus> keysStatus;
+ KeyStatus keyStatus;
- sendKeysChange(toVector(scope), keysStatus, true);
- }
+ std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+ keyStatus.keyId = keyId1;
+ keyStatus.type = V1_0::KeyStatusType::USABLE;
+ keysStatus.push_back(keyStatus);
- installSecureStop(scope);
+ std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+ keyStatus.keyId = keyId2;
+ keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+ keysStatus.push_back(keyStatus);
- // Returns status and empty keySetId
- _hidl_cb(status, toHidlVec(keySetId));
+ sendKeysChange(sessionId, keysStatus, true);
+
+ installSecureStop(sessionId);
+ } else {
+ ALOGE("Failed to add key, error=%d", status);
+ }
+ } // keyType::STREAMING || keyType::OFFLINE
+
+ std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
+ _hidl_cb(status, toHidlVec(keySetIdVec));
return Void();
}
+Return<Status> DrmPlugin::restoreKeys(
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& keySetId) {
+ if (sessionId.size() == 0 || keySetId.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ DeviceFiles::LicenseState licenseState;
+ std::string keySetIdString(keySetId.begin(), keySetId.end());
+ std::string offlineLicense;
+ Status status = Status::OK;
+ if (!mFileHandle.RetrieveLicense(keySetIdString, &licenseState, &offlineLicense)) {
+ ALOGE("Failed to restore offline license");
+ return Status::ERROR_DRM_NO_LICENSE;
+ }
+
+ if (DeviceFiles::kLicenseStateUnknown == licenseState ||
+ DeviceFiles::kLicenseStateReleasing == licenseState) {
+ ALOGE("Invalid license state=%d", licenseState);
+ return Status::ERROR_DRM_NO_LICENSE;
+ }
+
+ sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+ status = session->provideKeyResponse(std::vector<uint8_t>(offlineLicense.begin(),
+ offlineLicense.end()));
+ if (status != Status::OK) {
+ ALOGE("Failed to restore keys");
+ }
+ return status;
+}
+
Return<void> DrmPlugin::getPropertyString(
const hidl_string& propertyName, getPropertyString_cb _hidl_cb) {
std::string name(propertyName.c_str());
@@ -346,6 +466,9 @@
if (name == kDeviceIdKey) {
ALOGD("Cannot set immutable property: %s", name.c_str());
return Status::BAD_VALUE;
+ } else if (name == kClientIdKey) {
+ mByteArrayProperties[kClientIdKey] = toVector(value);
+ return Status::OK;
}
// Setting of undefined properties is not supported
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index e2bb651..dd1689f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -45,21 +45,22 @@
}
Status InitDataParser::parse(const std::vector<uint8_t>& initData,
- const std::string& type,
+ const std::string& mimeType,
+ V1_0::KeyType keyType,
std::vector<uint8_t>* licenseRequest) {
// Build a list of the key IDs
std::vector<const uint8_t*> keyIds;
- if (type == kIsoBmffVideoMimeType ||
- type == kIsoBmffAudioMimeType ||
- type == kCencInitDataFormat) {
+ if (mimeType == kIsoBmffVideoMimeType ||
+ mimeType == kIsoBmffAudioMimeType ||
+ mimeType == kCencInitDataFormat) {
Status res = parsePssh(initData, &keyIds);
if (res != Status::OK) {
return res;
}
- } else if (type == kWebmVideoMimeType ||
- type == kWebmAudioMimeType ||
- type == kWebmInitDataFormat) {
+ } else if (mimeType == kWebmVideoMimeType ||
+ mimeType == kWebmAudioMimeType ||
+ mimeType == kWebmInitDataFormat) {
// WebM "init data" is just a single key ID
if (initData.size() != kKeyIdSize) {
return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -69,8 +70,12 @@
return Status::ERROR_DRM_CANNOT_HANDLE;
}
+ if (keyType == V1_0::KeyType::RELEASE) {
+ // restore key
+ }
+
// Build the request
- std::string requestJson = generateRequest(keyIds);
+ std::string requestJson = generateRequest(keyType, keyIds);
std::vector<uint8_t> requestJsonVec = StrToVector(requestJson);
licenseRequest->clear();
@@ -131,9 +136,11 @@
return Status::OK;
}
-std::string InitDataParser::generateRequest(const std::vector<const uint8_t*>& keyIds) {
+std::string InitDataParser::generateRequest(V1_0::KeyType keyType,
+ const std::vector<const uint8_t*>& keyIds) {
const std::string kRequestPrefix("{\"kids\":[");
- const std::string kRequestSuffix("],\"type\":\"temporary\"}");
+ const std::string kTemporarySession("],\"type\":\"temporary\"}");
+ const std::string kPersistentSession("],\"type\":\"persistent-license\"}");
std::string request(kRequestPrefix);
std::string encodedId;
@@ -147,7 +154,11 @@
request.append(encodedId);
request.push_back('\"');
}
- request.append(kRequestSuffix);
+ if (keyType == V1_0::KeyType::STREAMING) {
+ request.append(kTemporarySession);
+ } else if (keyType == V1_0::KeyType::OFFLINE) {
+ request.append(kPersistentSession);
+ }
// Android's Base64 encoder produces padding. EME forbids padding.
const char kBase64Padding = '=';
diff --git a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
index cccb41e..1c32b1b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
@@ -22,12 +22,15 @@
#include "Base64.h"
namespace {
+const std::string kBase64Padding("=");
const std::string kKeysTag("keys");
const std::string kKeyTypeTag("kty");
-const std::string kSymmetricKeyValue("oct");
const std::string kKeyTag("k");
const std::string kKeyIdTag("kid");
-const std::string kBase64Padding("=");
+const std::string kMediaSessionType("type");
+const std::string kPersistentLicenseSession("persistent-license");
+const std::string kSymmetricKeyValue("oct");
+const std::string kTemporaryLicenseSession("temporary");
}
namespace android {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
new file mode 100644
index 0000000..47f188d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -0,0 +1,81 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+
+#include <utils/Log.h>
+
+#include <string>
+
+#include "MemoryFileSystem.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+std::string MemoryFileSystem::GetFileName(const std::string& path) {
+ size_t index = path.find_last_of("/");
+ if (index != std::string::npos) {
+ return path.substr(index+1);
+ } else {
+ return path;
+ }
+}
+
+bool MemoryFileSystem::FileExists(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ return result != mMemoryFileSystem.end();
+}
+
+ssize_t MemoryFileSystem::GetFileSize(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ return static_cast<ssize_t>(result->second.getFileSize());
+ } else {
+ ALOGE("Failed to get size for %s", fileName.c_str());
+ return -1;
+ }
+}
+
+size_t MemoryFileSystem::Read(const std::string& path, std::string* buffer) {
+ std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ std::string serializedHashFile = result->second.getContent();
+ buffer->assign(serializedHashFile);
+ return buffer->size();
+ } else {
+ ALOGE("Failed to read from %s", path.c_str());
+ return -1;
+ }
+}
+
+size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
+ std::string key = GetFileName(path);
+ mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
+ return memoryFile.getFileSize();
+}
+
+bool MemoryFileSystem::RemoveFile(const std::string& fileName) {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(result);
+ return true;
+ } else {
+ ALOGE("Cannot find license to remove: %s", fileName.c_str());
+ return false;
+ }
+}
+
+bool MemoryFileSystem::RemoveAllFiles() {
+ mMemoryFileSystem.clear();
+ return mMemoryFileSystem.empty();
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
index 07c9269..41a8374 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
@@ -42,9 +42,10 @@
Status Session::getKeyRequest(
const std::vector<uint8_t>& initData,
const std::string& mimeType,
+ V1_0::KeyType keyType,
std::vector<uint8_t>* keyRequest) const {
InitDataParser parser;
- return parser.parse(initData, mimeType, keyRequest);
+ return parser.parse(initData, mimeType, keyType, keyRequest);
}
Status Session::provideKeyResponse(const std::vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index d65b25c..3d6a4a9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -28,7 +28,7 @@
static const std::string kVendorKey("vendor");
static const std::string kVendorValue("Google");
static const std::string kVersionKey("version");
-static const std::string kVersionValue("1.1");
+static const std::string kVersionValue("1.2");
static const std::string kPluginDescriptionKey("description");
static const std::string kPluginDescriptionValue("ClearKey CDM");
static const std::string kAlgorithmsKey("algorithms");
@@ -40,6 +40,10 @@
static const uint8_t kTestDeviceIdData[] =
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+// settable byte array property
+static const std::string kClientIdKey("clientId");
+
// TODO stub out metrics for nw
static const std::string kMetricsKey("metrics");
static const uint8_t kMetricsData[] = { 0 };
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
new file mode 100644
index 0000000..a201e88
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
@@ -0,0 +1,67 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+#ifndef CLEARKEY_DEVICE_FILES_H_
+#define CLEARKEY_DEVICE_FILES_H_
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "protos/DeviceFiles.pb.h"
+#include "ClearKeyTypes.h"
+#include "MemoryFileSystem.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+class DeviceFiles {
+ public:
+ typedef enum {
+ kLicenseStateActive,
+ kLicenseStateReleasing,
+ kLicenseStateUnknown,
+ } LicenseState;
+
+ DeviceFiles() {};
+ virtual ~DeviceFiles() {};
+
+ virtual bool StoreLicense(const std::string& keySetId, LicenseState state,
+ const std::string& keyResponse);
+
+ virtual bool RetrieveLicense(
+ const std::string& key_set_id, LicenseState* state, std::string* offlineLicense);
+
+ virtual bool LicenseExists(const std::string& keySetId);
+
+ virtual bool DeleteAllLicenses();
+
+ private:
+ bool FileExists(const std::string& path) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ bool RemoveFile(const std::string& fileName);
+
+ bool RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile);
+ bool StoreFileRaw(const std::string& fileName, const std::string& serializedFile);
+ bool StoreFileWithHash(const std::string& fileName, const std::string& serializedFile);
+
+ MemoryFileSystem mFileHandle;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_DEVICE_FILES_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index fb0695a..12d8608 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <map>
+#include "DeviceFiles.h"
#include "SessionLibrary.h"
#include "Utils.h"
@@ -53,7 +54,7 @@
struct DrmPlugin : public IDrmPlugin {
explicit DrmPlugin(SessionLibrary* sessionLibrary);
- virtual ~DrmPlugin() {}
+ virtual ~DrmPlugin() { mFileHandle.DeleteAllLicenses(); }
Return<void> openSession(openSession_cb _hidl_cb) override;
Return<void> openSession_1_1(SecurityLevel securityLevel,
@@ -91,13 +92,7 @@
Return<Status> restoreKeys(
const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<uint8_t>& keySetId) {
-
- if (sessionId.size() == 0 || keySetId.size() == 0) {
- return Status::BAD_VALUE;
- }
- return Status::ERROR_DRM_CANNOT_HANDLE;
- }
+ const hidl_vec<uint8_t>& keySetId) override;
Return<void> queryKeyStatus(
const hidl_vec<uint8_t>& sessionId,
@@ -300,6 +295,7 @@
private:
void initProperties();
void installSecureStop(const hidl_vec<uint8_t>& sessionId);
+ bool makeKeySetId(std::string* keySetId);
void setPlayPolicy();
Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
@@ -331,6 +327,8 @@
int64_t mCloseSessionNotOpenedCount;
uint32_t mNextSecureStopId;
+ DeviceFiles mFileHandle;
+
CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
};
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
index 3189c4a..7d7abf2 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
@@ -34,7 +34,8 @@
InitDataParser() {}
Status parse(const std::vector<uint8_t>& initData,
- const std::string& type,
+ const std::string& mimeType,
+ V1_0::KeyType keyType,
std::vector<uint8_t>* licenseRequest);
private:
@@ -43,7 +44,7 @@
Status parsePssh(const std::vector<uint8_t>& initData,
std::vector<const uint8_t*>* keyIds);
- std::string generateRequest(
+ std::string generateRequest(V1_0::KeyType keyType,
const std::vector<const uint8_t*>& keyIds);
};
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
new file mode 100644
index 0000000..db368d7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
@@ -0,0 +1,65 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+#ifndef CLEARKEY_MEMORY_FILE_SYSTEM_H_
+#define CLEARKEY_MEMORY_FILE_SYSTEM_H_
+
+#include <map>
+#include <string>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+// Using android file system requires clearkey plugin to update
+// its sepolicy. However, we are unable to update sepolicy for
+// older vendor partitions. To provide backward compatibility,
+// clearkey plugin implements a very simple file system in memory.
+// This memory file system does not support directory structure.
+class MemoryFileSystem {
+ public:
+ struct MemoryFile {
+ std::string fileName; // excludes path
+ std::string content;
+ size_t fileSize;
+
+ std::string getContent() const { return content; }
+ size_t getFileSize() const { return fileSize; }
+ void setContent(const std::string& file) { content = file; }
+ void setFileName(const std::string& name) { fileName = name; }
+ void setFileSize(size_t size) { fileSize = size; }
+ };
+
+ MemoryFileSystem() {};
+ virtual ~MemoryFileSystem() {};
+
+ bool FileExists(const std::string& fileName) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ size_t Read(const std::string& pathName, std::string* buffer);
+ bool RemoveAllFiles();
+ bool RemoveFile(const std::string& fileName);
+ size_t Write(const std::string& pathName, const MemoryFile& memoryFile);
+
+ private:
+ // License file name is made up of a unique keySetId, therefore,
+ // the filename can be used as the key to locate licenses in the
+ // memory file system.
+ std::map<std::string, MemoryFile> mMemoryFileSystem;
+
+ std::string GetFileName(const std::string& path);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(MemoryFileSystem);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // CLEARKEY_MEMORY_FILE_SYSTEM_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
index cddfca5..1064dc7 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
@@ -42,8 +42,9 @@
const std::vector<uint8_t>& sessionId() const { return mSessionId; }
Status getKeyRequest(
- const std::vector<uint8_t>& mimeType,
- const std::string& initDataType,
+ const std::vector<uint8_t>& initDataType,
+ const std::string& mimeType,
+ V1_0::KeyType keyType,
std::vector<uint8_t>* keyRequest) const;
Status provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto b/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto
new file mode 100644
index 0000000..145ac5b
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto
@@ -0,0 +1,47 @@
+// ----------------------------------------------------------------------------
+// device_files.proto
+// ----------------------------------------------------------------------------
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+// Description:
+// Format of various files stored at the device.
+//
+syntax = "proto2";
+
+package android.hardware.drm.V1_1.clearkey;
+
+// need this if we are using libprotobuf-cpp-2.3.0-lite
+option optimize_for = LITE_RUNTIME;
+
+message License {
+ enum LicenseState {
+ ACTIVE = 1;
+ RELEASING = 2;
+ }
+
+ optional LicenseState state = 1;
+ optional bytes license = 2;
+}
+
+message OfflineFile {
+ enum FileType {
+ LICENSE = 1;
+ }
+
+ enum FileVersion {
+ VERSION_1 = 1;
+ }
+
+ optional FileType type = 1;
+ optional FileVersion version = 2 [default = VERSION_1];
+ optional License license = 3;
+
+}
+
+message HashedFile {
+ optional bytes file = 1;
+ // A raw (not hex-encoded) SHA256, taken over the bytes of 'file'.
+ optional bytes hash = 2;
+}
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
index b071a58..38962e5 100644
--- a/include/media/MediaExtractorPluginApi.h
+++ b/include/media/MediaExtractorPluginApi.h
@@ -18,7 +18,7 @@
#define MEDIA_EXTRACTOR_PLUGIN_API_H_
#include <utils/Errors.h> // for status_t
-
+#include <media/NdkMediaError.h>
struct AMediaFormat;
namespace android {
@@ -62,10 +62,10 @@
void *data;
void (*free)(void *data);
- status_t (*start)(void *data);
- status_t (*stop)(void *data);
- status_t (*getFormat)(void *data, AMediaFormat *format);
- status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
+ media_status_t (*start)(void *data);
+ media_status_t (*stop)(void *data);
+ media_status_t (*getFormat)(void *data, AMediaFormat *format);
+ media_status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
bool (*supportsNonBlockingRead)(void *data);
};
@@ -93,14 +93,14 @@
void (*free)(void *data);
size_t (*countTracks)(void *data);
CMediaTrackV2* (*getTrack)(void *data, size_t index);
- status_t (*getTrackMetaData)(
+ media_status_t (*getTrackMetaData)(
void *data,
AMediaFormat *meta,
size_t index, uint32_t flags);
- status_t (*getMetaData)(void *data, AMediaFormat *meta);
+ media_status_t (*getMetaData)(void *data, AMediaFormat *meta);
uint32_t (*flags)(void *data);
- status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+ media_status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
const char * (*name)(void *data);
};
diff --git a/include/media/MediaExtractorPluginHelper.h b/include/media/MediaExtractorPluginHelper.h
index d76d5f8..858c575 100644
--- a/include/media/MediaExtractorPluginHelper.h
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -106,9 +106,9 @@
class MediaTrackHelperV2 {
public:
virtual ~MediaTrackHelperV2() {};
- virtual status_t start() = 0;
- virtual status_t stop() = 0;
- virtual status_t getFormat(AMediaFormat *format) = 0;
+ virtual media_status_t start() = 0;
+ virtual media_status_t stop() = 0;
+ virtual media_status_t getFormat(AMediaFormat *format) = 0;
class ReadOptions {
public:
@@ -140,7 +140,7 @@
int64_t mSeekPosUs;
};
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
virtual bool supportsNonBlockingRead() { return false; }
};
@@ -151,17 +151,17 @@
wrapper->free = [](void *data) -> void {
delete (MediaTrackHelperV2*)(data);
};
- wrapper->start = [](void *data) -> status_t {
+ wrapper->start = [](void *data) -> media_status_t {
return ((MediaTrackHelperV2*)data)->start();
};
- wrapper->stop = [](void *data) -> status_t {
+ wrapper->stop = [](void *data) -> media_status_t {
return ((MediaTrackHelperV2*)data)->stop();
};
- wrapper->getFormat = [](void *data, AMediaFormat *meta) -> status_t {
+ wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
return ((MediaTrackHelperV2*)data)->getFormat(meta);
};
wrapper->read = [](void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs)
- -> status_t {
+ -> media_status_t {
MediaTrackHelperV2::ReadOptions opts(options, seekPosUs);
return ((MediaTrackHelperV2*)data)->read(buffer, &opts);
};
@@ -268,13 +268,13 @@
enum GetTrackMetaDataFlags {
kIncludeExtensiveMetaData = 1
};
- virtual status_t getTrackMetaData(
+ virtual media_status_t getTrackMetaData(
AMediaFormat *meta,
size_t index, uint32_t flags = 0) = 0;
// Return container specific meta-data. The default implementation
// returns an empty metadata object.
- virtual status_t getMetaData(AMediaFormat *meta) = 0;
+ virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
enum Flags {
CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
@@ -289,8 +289,8 @@
return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
};
- virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
- return INVALID_OPERATION;
+ virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
virtual const char * name() { return "<unspecified>"; }
@@ -318,12 +318,12 @@
wrapper->getTrackMetaData = [](
void *data,
AMediaFormat *meta,
- size_t index, uint32_t flags) -> status_t {
+ size_t index, uint32_t flags) -> media_status_t {
return ((MediaExtractorPluginHelperV2*)data)->getTrackMetaData(meta, index, flags);
};
wrapper->getMetaData = [](
void *data,
- AMediaFormat *meta) -> status_t {
+ AMediaFormat *meta) -> media_status_t {
return ((MediaExtractorPluginHelperV2*)data)->getMetaData(meta);
};
wrapper->flags = [](
@@ -331,7 +331,7 @@
return ((MediaExtractorPluginHelperV2*)data)->flags();
};
wrapper->setMediaCas = [](
- void *data, const uint8_t *casToken, size_t size) -> status_t {
+ void *data, const uint8_t *casToken, size_t size) -> media_status_t {
return ((MediaExtractorPluginHelperV2*)data)->setMediaCas(casToken, size);
};
wrapper->name = [](
diff --git a/media/ndk/NdkMediaErrorPriv.h b/include/media/NdkMediaErrorPriv.h
similarity index 100%
rename from media/ndk/NdkMediaErrorPriv.h
rename to include/media/NdkMediaErrorPriv.h
diff --git a/include/media/VorbisComment.h b/include/media/VorbisComment.h
deleted file mode 120000
index adaa489..0000000
--- a/include/media/VorbisComment.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/VorbisComment.h
\ No newline at end of file
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
index 5fd8eb2..ea1aea6 100644
--- a/include/soundtrigger/ISoundTrigger.h
+++ b/include/soundtrigger/ISoundTrigger.h
@@ -40,6 +40,8 @@
virtual status_t startRecognition(sound_model_handle_t handle,
const sp<IMemory>& dataMemory) = 0;
virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
+ virtual status_t getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory) = 0;
};
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index 7a29e31..dcf9ce8 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -52,6 +52,7 @@
status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
status_t stopRecognition(sound_model_handle_t handle);
+ status_t getModelState(sound_model_handle_t handle, sp<IMemory>& eventMemory);
// BpSoundTriggerClient
virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 1ca0fdc..f05c84b 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -4,7 +4,6 @@
LOCAL_SRC_FILES := \
main_audioserver.cpp \
- ../libaudioclient/aidl/android/media/IAudioRecord.aidl
LOCAL_SHARED_LIBRARIES := \
libaaudioservice \
@@ -41,9 +40,6 @@
$(call include-path-for, audio-utils) \
external/sonic \
-LOCAL_AIDL_INCLUDES := \
- frameworks/av/media/libaudioclient/aidl
-
# If AUDIOSERVER_MULTILIB in device.mk is non-empty then it is used to control
# the LOCAL_MULTILIB for all audioserver exclusive libraries.
# This is relevant for 64 bit architectures where either or both
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 1589131..f278107 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -26,26 +26,25 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
namespace android {
-class AACSource : public MediaTrackHelper {
+class AACSource : public MediaTrackHelperV2 {
public:
AACSource(
DataSourceHelper *source,
- MetaDataBase &meta,
+ AMediaFormat *meta,
const Vector<uint64_t> &offset_vector,
int64_t frame_duration_us);
- virtual status_t start();
- virtual status_t stop();
+ virtual media_status_t start();
+ virtual media_status_t stop();
- virtual status_t getFormat(MetaDataBase&);
+ virtual media_status_t getFormat(AMediaFormat*);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -54,7 +53,7 @@
private:
static const size_t kMaxFrameSize;
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
off64_t mOffset;
int64_t mCurrentTimeUs;
@@ -150,6 +149,7 @@
}
channel = (header[0] & 0x1) << 2 | (header[1] >> 6);
+ mMeta = AMediaFormat_new();
MakeAACCodecSpecificData(mMeta, profile, sf_index, channel);
off64_t streamSize, numFrames = 0;
@@ -173,29 +173,30 @@
// Round up and get the duration
mFrameDurationUs = (1024 * 1000000ll + (sr - 1)) / sr;
duration = numFrames * mFrameDurationUs;
- mMeta.setInt64(kKeyDuration, duration);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
}
mInitCheck = OK;
}
AACExtractor::~AACExtractor() {
+ AMediaFormat_delete(mMeta);
}
-status_t AACExtractor::getMetaData(MetaDataBase &meta) {
- meta.clear();
+media_status_t AACExtractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_clear(meta);
if (mInitCheck == OK) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
}
- return OK;
+ return AMEDIA_OK;
}
size_t AACExtractor::countTracks() {
return mInitCheck == OK ? 1 : 0;
}
-MediaTrackHelper *AACExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AACExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -203,13 +204,12 @@
return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs);
}
-status_t AACExtractor::getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t /* flags */) {
+media_status_t AACExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index != 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- meta = mMeta;
- return OK;
+ return AMediaFormat_copy(meta, mMeta);
}
////////////////////////////////////////////////////////////////////////////////
@@ -219,7 +219,7 @@
AACSource::AACSource(
DataSourceHelper *source,
- MetaDataBase &meta,
+ AMediaFormat *meta,
const Vector<uint64_t> &offset_vector,
int64_t frame_duration_us)
: mDataSource(source),
@@ -238,7 +238,7 @@
}
}
-status_t AACSource::start() {
+media_status_t AACSource::start() {
CHECK(!mStarted);
if (mOffsetVector.empty()) {
@@ -252,25 +252,24 @@
mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t AACSource::stop() {
+media_status_t AACSource::stop() {
CHECK(mStarted);
delete mGroup;
mGroup = NULL;
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t AACSource::getFormat(MetaDataBase &meta) {
- meta = mMeta;
- return OK;
+media_status_t AACSource::getFormat(AMediaFormat *meta) {
+ return AMediaFormat_copy(meta, mMeta);
}
-status_t AACSource::read(
+media_status_t AACSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@@ -281,7 +280,7 @@
int64_t seekFrame = seekTimeUs / mFrameDurationUs;
if (seekFrame < 0 || seekFrame >= (int64_t)mOffsetVector.size()) {
android_errorWriteLog(0x534e4554, "70239507");
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
mCurrentTimeUs = seekFrame * mFrameDurationUs;
@@ -291,13 +290,13 @@
size_t frameSize, frameSizeWithoutHeader, headerSize;
if ((frameSize = getAdtsFrameLength(mDataSource, mOffset, &headerSize)) == 0) {
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
frameSizeWithoutHeader = frameSize - headerSize;
@@ -306,7 +305,7 @@
buffer->release();
buffer = NULL;
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
}
buffer->set_range(0, frameSizeWithoutHeader);
@@ -317,19 +316,19 @@
mCurrentTimeUs += mFrameDurationUs;
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *meta) {
off64_t offset = *static_cast<off64_t*>(meta);
- return wrap(new AACExtractor(new DataSourceHelper(source), offset));
+ return wrapV2(new AACExtractor(new DataSourceHelper(source), offset));
}
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
CDataSource *source, float *confidence, void **meta,
FreeMetaFunc *freeMeta) {
off64_t pos = 0;
@@ -389,11 +388,11 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
1, // version
"AAC Extractor",
- { Sniff }
+ { .v2 = Sniff }
};
}
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 7afdeb7..3b11f95 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -20,7 +20,7 @@
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
#include <utils/Vector.h>
@@ -29,15 +29,15 @@
struct AMessage;
class String8;
-class AACExtractor : public MediaExtractorPluginHelper {
+class AACExtractor : public MediaExtractorPluginHelperV2 {
public:
AACExtractor(DataSourceHelper *source, off64_t offset);
virtual size_t countTracks();
- virtual MediaTrackHelper *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "AACExtractor"; }
protected:
@@ -45,7 +45,7 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
status_t mInitCheck;
Vector<uint64_t> mOffsetVector;
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 5f05b42..42b0a64 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -9,6 +9,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 99d24c9..511b14d 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -38,12 +38,12 @@
const off64_t *offset_table,
size_t offset_table_length);
- virtual status_t start();
- virtual status_t stop();
+ virtual media_status_t start();
+ virtual media_status_t stop();
- virtual status_t getFormat(AMediaFormat *);
+ virtual media_status_t getFormat(AMediaFormat *);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -96,23 +96,23 @@
return frameSize;
}
-static status_t getFrameSizeByOffset(DataSourceHelper *source,
+static media_status_t getFrameSizeByOffset(DataSourceHelper *source,
off64_t offset, bool isWide, size_t *frameSize) {
uint8_t header;
ssize_t count = source->readAt(offset, &header, 1);
if (count == 0) {
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
} else if (count < 0) {
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
}
unsigned FT = (header >> 3) & 0x0f;
*frameSize = getFrameSize(isWide, FT);
if (*frameSize == 0) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
- return OK;
+ return AMEDIA_OK;
}
static bool SniffAMR(
@@ -194,7 +194,7 @@
AMediaFormat_delete(mMeta);
}
-status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
+media_status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
AMediaFormat_clear(meta);
if (mInitCheck == OK) {
@@ -202,7 +202,7 @@
AMEDIAFORMAT_KEY_MIME, mIsWide ? "audio/amr-wb" : "audio/amr");
}
- return OK;
+ return AMEDIA_OK;
}
size_t AMRExtractor::countTracks() {
@@ -218,13 +218,12 @@
mOffsetTable, mOffsetTableLength);
}
-status_t AMRExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
+media_status_t AMRExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index != 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- AMediaFormat_copy(meta, mMeta);
- return OK;
+ return AMediaFormat_copy(meta, mMeta);
}
////////////////////////////////////////////////////////////////////////////////
@@ -251,7 +250,7 @@
}
}
-status_t AMRSource::start() {
+media_status_t AMRSource::start() {
CHECK(!mStarted);
mOffset = mIsWide ? 9 : 6;
@@ -260,25 +259,24 @@
mGroup->add_buffer(MediaBufferBase::Create(128));
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t AMRSource::stop() {
+media_status_t AMRSource::stop() {
CHECK(mStarted);
delete mGroup;
mGroup = NULL;
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t AMRSource::getFormat(AMediaFormat *meta) {
- AMediaFormat_copy(meta, mMeta);
- return OK;
+media_status_t AMRSource::getFormat(AMediaFormat *meta) {
+ return AMediaFormat_copy(meta, mMeta);
}
-status_t AMRSource::read(
+media_status_t AMRSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@@ -297,7 +295,7 @@
mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6);
for (size_t i = 0; i< seekFrame - index * 50; i++) {
- status_t err;
+ media_status_t err;
if ((err = getFrameSizeByOffset(mDataSource, mOffset,
mIsWide, &size)) != OK) {
return err;
@@ -310,7 +308,7 @@
ssize_t n = mDataSource->readAt(mOffset, &header, 1);
if (n < 1) {
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
if (header & 0x83) {
@@ -318,20 +316,20 @@
ALOGE("padding bits must be 0, header is 0x%02x", header);
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
unsigned FT = (header >> 3) & 0x0f;
size_t frameSize = getFrameSize(mIsWide, FT);
if (frameSize == 0) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
@@ -341,11 +339,11 @@
buffer = NULL;
if (n < 0) {
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
} else {
// only partial frame is available, treat it as EOS.
mOffset += n;
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
}
@@ -358,7 +356,7 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 145fe08..44b2cbd 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -35,9 +35,9 @@
virtual size_t countTracks();
virtual MediaTrackHelperV2 *getTrack(size_t index);
- virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(AMediaFormat *meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "AMRExtractor"; }
protected:
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 6282793..eda7b61 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -10,11 +10,14 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
"libFLAC",
"libstagefright_foundation",
+ "libstagefright_metadatautils",
+ "libutils",
],
name: "libflacextractor",
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 337ada5..fcfdaff 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -25,7 +25,7 @@
#include "FLAC/stream_decoder.h"
#include <media/MediaExtractorPluginApi.h>
-#include <media/VorbisComment.h>
+#include <media/NdkMediaFormat.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
@@ -33,24 +33,25 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MediaBufferBase.h>
namespace android {
class FLACParser;
-class FLACSource : public MediaTrackHelper {
+class FLACSource : public MediaTrackHelperV2 {
public:
FLACSource(
DataSourceHelper *dataSource,
- MetaDataBase &meta);
+ AMediaFormat *meta);
- virtual status_t start();
- virtual status_t stop();
- virtual status_t getFormat(MetaDataBase &meta);
+ virtual media_status_t start();
+ virtual media_status_t stop();
+ virtual media_status_t getFormat(AMediaFormat *meta);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -58,7 +59,7 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase mTrackMetadata;
+ AMediaFormat *mTrackMetadata;
FLACParser *mParser;
bool mInitCheck;
bool mStarted;
@@ -81,8 +82,8 @@
explicit FLACParser(
DataSourceHelper *dataSource,
// If metadata pointers aren't provided, we don't fill them
- MetaDataBase *fileMetadata = 0,
- MetaDataBase *trackMetadata = 0);
+ AMediaFormat *fileMetadata = 0,
+ AMediaFormat *trackMetadata = 0);
virtual ~FLACParser();
@@ -119,8 +120,8 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase *mFileMetadata;
- MetaDataBase *mTrackMetadata;
+ AMediaFormat *mFileMetadata;
+ AMediaFormat *mTrackMetadata;
bool mInitCheck;
// media buffers
@@ -364,9 +365,8 @@
case FLAC__METADATA_TYPE_PICTURE:
if (mFileMetadata != 0) {
const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
- mFileMetadata->setData(kKeyAlbumArt,
- MetaData::TYPE_NONE, p->data, p->data_length);
- mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+ AMediaFormat_setBuffer(mFileMetadata, AMEDIAFORMAT_KEY_ALBUMART,
+ p->data, p->data_length);
}
break;
default:
@@ -488,8 +488,8 @@
FLACParser::FLACParser(
DataSourceHelper *dataSource,
- MetaDataBase *fileMetadata,
- MetaDataBase *trackMetadata)
+ AMediaFormat *fileMetadata,
+ AMediaFormat *trackMetadata)
: mDataSource(dataSource),
mFileMetadata(fileMetadata),
mTrackMetadata(trackMetadata),
@@ -615,20 +615,25 @@
}
// populate track metadata
if (mTrackMetadata != 0) {
- mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
- mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
- mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+ AMediaFormat_setString(mTrackMetadata,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+ AMediaFormat_setInt32(mTrackMetadata,
+ AMEDIAFORMAT_KEY_CHANNEL_COUNT, getChannels());
+ AMediaFormat_setInt32(mTrackMetadata,
+ AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
+ AMediaFormat_setInt32(mTrackMetadata,
+ AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
// sample rate is non-zero, so division by zero not possible
- mTrackMetadata->setInt64(kKeyDuration,
- (getTotalSamples() * 1000000LL) / getSampleRate());
+ AMediaFormat_setInt64(mTrackMetadata,
+ AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
}
} else {
ALOGE("missing STREAMINFO");
return NO_INIT;
}
if (mFileMetadata != 0) {
- mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+ AMediaFormat_setString(mFileMetadata,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
}
return OK;
}
@@ -709,7 +714,7 @@
FLACSource::FLACSource(
DataSourceHelper *dataSource,
- MetaDataBase &trackMetadata)
+ AMediaFormat *trackMetadata)
: mDataSource(dataSource),
mTrackMetadata(trackMetadata),
mParser(0),
@@ -731,7 +736,7 @@
delete mParser;
}
-status_t FLACSource::start()
+media_status_t FLACSource::start()
{
ALOGV("FLACSource::start");
@@ -739,10 +744,10 @@
mParser->allocateBuffers();
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t FLACSource::stop()
+media_status_t FLACSource::stop()
{
ALOGV("FLACSource::stop");
@@ -750,16 +755,15 @@
mParser->releaseBuffers();
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t FLACSource::getFormat(MetaDataBase &meta)
+media_status_t FLACSource::getFormat(AMediaFormat *meta)
{
- meta = mTrackMetadata;
- return OK;
+ return AMediaFormat_copy(meta, mTrackMetadata);
}
-status_t FLACSource::read(
+media_status_t FLACSource::read(
MediaBufferBase **outBuffer, const ReadOptions *options)
{
MediaBufferBase *buffer;
@@ -783,7 +787,7 @@
buffer = mParser->readBuffer();
}
*outBuffer = buffer;
- return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+ return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
}
// FLACExtractor
@@ -796,7 +800,9 @@
{
ALOGV("FLACExtractor::FLACExtractor");
// FLACParser will fill in the metadata for us
- mParser = new FLACParser(mDataSource, &mFileMetadata, &mTrackMetadata);
+ mFileMetadata = AMediaFormat_new();
+ mTrackMetadata = AMediaFormat_new();
+ mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
mInitCheck = mParser->initCheck();
}
@@ -805,6 +811,8 @@
ALOGV("~FLACExtractor::FLACExtractor");
delete mParser;
delete mDataSource;
+ AMediaFormat_delete(mFileMetadata);
+ AMediaFormat_delete(mTrackMetadata);
}
size_t FLACExtractor::countTracks()
@@ -812,7 +820,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrackHelper *FLACExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
@@ -820,20 +828,18 @@
return new FLACSource(mDataSource, mTrackMetadata);
}
-status_t FLACExtractor::getTrackMetaData(
- MetaDataBase &meta,
+media_status_t FLACExtractor::getTrackMetaData(
+ AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index > 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- meta = mTrackMetadata;
- return OK;
+ return AMediaFormat_copy(meta, mTrackMetadata);
}
-status_t FLACExtractor::getMetaData(MetaDataBase &meta)
+media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
{
- meta = mFileMetadata;
- return OK;
+ return AMediaFormat_copy(meta, mFileMetadata);
}
// Sniffer
@@ -862,22 +868,22 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
1,
"FLAC Extractor",
{
- [](
+ .v2 = [](
CDataSource *source,
float *confidence,
void **,
- FreeMetaFunc *) -> CreatorFunc {
+ FreeMetaFunc *) -> CreatorFuncV2 {
DataSourceHelper helper(source);
if (SniffFLAC(&helper, confidence)) {
return [](
CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+ void *) -> CMediaExtractorV2* {
+ return wrapV2(new FLACExtractor(new DataSourceHelper(source)));};
}
return NULL;
}
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 829f661..323307b 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -20,23 +20,23 @@
#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
#include <utils/String8.h>
namespace android {
class FLACParser;
-class FLACExtractor : public MediaExtractorPluginHelper {
+class FLACExtractor : public MediaExtractorPluginHelperV2 {
public:
explicit FLACExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrackHelper *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "FLACExtractor"; }
protected:
@@ -46,10 +46,10 @@
DataSourceHelper *mDataSource;
FLACParser *mParser;
status_t mInitCheck;
- MetaDataBase mFileMetadata;
+ AMediaFormat *mFileMetadata;
// There is only one track
- MetaDataBase mTrackMetadata;
+ AMediaFormat *mTrackMetadata;
FLACExtractor(const FLACExtractor &);
FLACExtractor &operator=(const FLACExtractor &);
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 9c2c863..cd39cec 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -40,11 +40,11 @@
MidiEngine &engine,
AMediaFormat *trackMetadata);
- virtual status_t start();
- virtual status_t stop();
- virtual status_t getFormat(AMediaFormat *);
+ virtual media_status_t start();
+ virtual media_status_t stop();
+ virtual media_status_t getFormat(AMediaFormat *);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -87,17 +87,17 @@
}
}
-status_t MidiSource::start()
+media_status_t MidiSource::start()
{
ALOGV("MidiSource::start");
CHECK(!mStarted);
mStarted = true;
mEngine.allocateBuffers();
- return OK;
+ return AMEDIA_OK;
}
-status_t MidiSource::stop()
+media_status_t MidiSource::stop()
{
ALOGV("MidiSource::stop");
@@ -105,16 +105,15 @@
mStarted = false;
mEngine.releaseBuffers();
- return OK;
+ return AMEDIA_OK;
}
-status_t MidiSource::getFormat(AMediaFormat *meta)
+media_status_t MidiSource::getFormat(AMediaFormat *meta)
{
- AMediaFormat_copy(meta, mTrackMetadata);
- return OK;
+ return AMediaFormat_copy(meta, mTrackMetadata);
}
-status_t MidiSource::read(
+media_status_t MidiSource::read(
MediaBufferBase **outBuffer, const ReadOptions *options)
{
ALOGV("MidiSource::read");
@@ -131,7 +130,7 @@
buffer = mEngine.readBuffer();
*outBuffer = buffer;
ALOGV("MidiSource::read %p done", this);
- return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+ return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
}
status_t MidiSource::init()
@@ -298,22 +297,20 @@
return new MidiSource(*mEngine, mTrackMetadata);
}
-status_t MidiExtractor::getTrackMetaData(
+media_status_t MidiExtractor::getTrackMetaData(
AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
ALOGV("MidiExtractor::getTrackMetaData");
if (mInitCheck != OK || index > 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- AMediaFormat_copy(meta, mTrackMetadata);
- return OK;
+ return AMediaFormat_copy(meta, mTrackMetadata);
}
-status_t MidiExtractor::getMetaData(AMediaFormat *meta)
+media_status_t MidiExtractor::getMetaData(AMediaFormat *meta)
{
ALOGV("MidiExtractor::getMetaData");
- AMediaFormat_copy(meta, mFileMetadata);
- return OK;
+ return AMediaFormat_copy(meta, mFileMetadata);
}
// Sniffer
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index d82c5be..412d6eb 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -58,9 +58,9 @@
virtual size_t countTracks();
virtual MediaTrackHelperV2 *getTrack(size_t index);
- virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(AMediaFormat *meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "MidiExtractor"; }
protected:
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 20ff6e2..e15cbdb 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -67,8 +67,12 @@
virtual int Length(long long* total, long long* available) {
off64_t size;
if (mSource->getSize(&size) != OK) {
- *total = -1;
- *available = (long long)((1ull << 63) - 1);
+ if (total) {
+ *total = -1;
+ }
+ if (available) {
+ *available = (long long)((1ull << 63) - 1);
+ }
return 0;
}
@@ -221,7 +225,8 @@
mExtractor->mTracks.itemAt(index).mTrackNum,
index),
mNALSizeLen(-1) {
- MetaDataBase &meta = mExtractor->mTracks.editItemAt(index).mMeta;
+ MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
+ MetaDataBase &meta = trackInfo.mMeta;
const char *mime;
CHECK(meta.findCString(kKeyMIMEType, &mime));
@@ -234,9 +239,9 @@
uint32_t dummy;
const uint8_t *avcc;
size_t avccSize;
- int32_t nalSizeLen = 0;
- if (meta.findInt32(kKeyNalLengthSize, &nalSizeLen)) {
- if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+ int32_t nalSizeLen = trackInfo.mNalLengthSize;
+ if (nalSizeLen >= 0) {
+ if (nalSizeLen <= 4) {
mNALSizeLen = nalSizeLen;
}
} else if (meta.findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
@@ -1226,7 +1231,7 @@
}
// Override the synthesized nal length size, which is arbitrary
- trackInfo->mMeta.setInt32(kKeyNalLengthSize, 0);
+ trackInfo->mNalLengthSize = 0;
return OK;
}
@@ -1343,6 +1348,7 @@
trackInfo->mEncrypted = false;
trackInfo->mHeader = NULL;
trackInfo->mHeaderLen = 0;
+ trackInfo->mNalLengthSize = -1;
for(size_t i = 0; i < track->GetContentEncodingCount(); i++) {
const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 43971a0..03fdeee 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -69,6 +69,7 @@
// in ~MatroskaExtractor.
unsigned char *mHeader;
size_t mHeaderLen;
+ int32_t mNalLengthSize;
const mkvparser::Track* getTrack() const;
const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const;
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index a3aeaca..1025c46 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -13,6 +13,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
"libstagefright_foundation",
],
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index eca5711..621fd03 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -207,19 +207,19 @@
return valid;
}
-class MP3Source : public MediaTrackHelper {
+class MP3Source : public MediaTrackHelperV2 {
public:
MP3Source(
- MetaDataBase &meta, DataSourceHelper *source,
+ AMediaFormat *meta, DataSourceHelper *source,
off64_t first_frame_pos, uint32_t fixed_header,
MP3Seeker *seeker);
- virtual status_t start();
- virtual status_t stop();
+ virtual media_status_t start();
+ virtual media_status_t stop();
- virtual status_t getFormat(MetaDataBase &meta);
+ virtual media_status_t getFormat(AMediaFormat *meta);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -227,7 +227,7 @@
private:
static const size_t kMaxFrameSize;
- MetaDataBase &mMeta;
+ AMediaFormat *mMeta;
DataSourceHelper *mDataSource;
off64_t mFirstFramePos;
uint32_t mFixedHeader;
@@ -283,6 +283,7 @@
mFixedHeader = header;
XINGSeeker *seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
+ mMeta = AMediaFormat_new();
if (seeker == NULL) {
mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
} else {
@@ -290,8 +291,8 @@
int encd = seeker->getEncoderDelay();
int encp = seeker->getEncoderPadding();
if (encd != 0 || encp != 0) {
- mMeta.setInt32(kKeyEncoderDelay, encd);
- mMeta.setInt32(kKeyEncoderPadding, encp);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, encd);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, encp);
}
}
@@ -327,21 +328,23 @@
switch (layer) {
case 1:
- mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+ AMediaFormat_setString(mMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
break;
case 2:
- mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ AMediaFormat_setString(mMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
break;
case 3:
- mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
break;
default:
TRESPASS();
}
- mMeta.setInt32(kKeySampleRate, sample_rate);
- mMeta.setInt32(kKeyBitRate, bitrate * 1000);
- mMeta.setInt32(kKeyChannelCount, num_channels);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sample_rate);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, bitrate * 1000);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, num_channels);
int64_t durationUs;
@@ -361,7 +364,7 @@
}
if (durationUs >= 0) {
- mMeta.setInt64(kKeyDuration, durationUs);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
}
mInitCheck = OK;
@@ -389,8 +392,8 @@
int32_t delay, padding;
if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
- mMeta.setInt32(kKeyEncoderDelay, delay);
- mMeta.setInt32(kKeyEncoderPadding, padding);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, delay);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, padding);
}
break;
}
@@ -404,13 +407,14 @@
MP3Extractor::~MP3Extractor() {
delete mSeeker;
delete mDataSource;
+ AMediaFormat_delete(mMeta);
}
size_t MP3Extractor::countTracks() {
return mInitCheck != OK ? 0 : 1;
}
-MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MP3Extractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -420,14 +424,14 @@
mSeeker);
}
-status_t MP3Extractor::getTrackMetaData(
- MetaDataBase &meta,
+media_status_t MP3Extractor::getTrackMetaData(
+ AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index != 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- meta = mMeta;
- return OK;
+ AMediaFormat_copy(meta, mMeta);
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
@@ -440,7 +444,7 @@
// Set our max frame size to the nearest power of 2 above this size (aka, 4kB)
const size_t MP3Source::kMaxFrameSize = (1 << 12); /* 4096 bytes */
MP3Source::MP3Source(
- MetaDataBase &meta, DataSourceHelper *source,
+ AMediaFormat *meta, DataSourceHelper *source,
off64_t first_frame_pos, uint32_t fixed_header,
MP3Seeker *seeker)
: mMeta(meta),
@@ -462,7 +466,7 @@
}
}
-status_t MP3Source::start() {
+media_status_t MP3Source::start() {
CHECK(!mStarted);
mGroup = new MediaBufferGroup;
@@ -477,10 +481,10 @@
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t MP3Source::stop() {
+media_status_t MP3Source::stop() {
CHECK(mStarted);
delete mGroup;
@@ -488,15 +492,14 @@
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t MP3Source::getFormat(MetaDataBase &meta) {
- meta = mMeta;
- return OK;
+media_status_t MP3Source::getFormat(AMediaFormat *meta) {
+ return AMediaFormat_copy(meta, mMeta);
}
-status_t MP3Source::read(
+media_status_t MP3Source::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@@ -509,11 +512,11 @@
if (mSeeker == NULL
|| !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
int32_t bitrate;
- if (!mMeta.findInt32(kKeyBitRate, &bitrate)) {
+ if (!AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
// bitrate is in bits/sec.
ALOGI("no bitrate");
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
mCurrentTimeUs = seekTimeUs;
@@ -530,7 +533,7 @@
MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
size_t frame_size;
@@ -543,7 +546,7 @@
buffer->release();
buffer = NULL;
- return (n < 0 ? n : ERROR_END_OF_STREAM);
+ return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
}
uint32_t header = U32_AT((const uint8_t *)buffer->data());
@@ -572,7 +575,7 @@
buffer->release();
buffer = NULL;
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
mCurrentPos = pos;
@@ -587,7 +590,7 @@
buffer->release();
buffer = NULL;
- return (n < 0 ? n : ERROR_END_OF_STREAM);
+ return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
}
buffer->set_range(0, frame_size);
@@ -602,40 +605,40 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
-status_t MP3Extractor::getMetaData(MetaDataBase &meta) {
- meta.clear();
+media_status_t MP3Extractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_clear(meta);
if (mInitCheck != OK) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- meta.setCString(kKeyMIMEType, "audio/mpeg");
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, "audio/mpeg");
DataSourceHelper helper(mDataSource);
ID3 id3(&helper);
if (!id3.isValid()) {
- return OK;
+ return AMEDIA_OK;
}
struct Map {
- int key;
+ const char *key;
const char *tag1;
const char *tag2;
};
static const Map kMap[] = {
- { kKeyAlbum, "TALB", "TAL" },
- { kKeyArtist, "TPE1", "TP1" },
- { kKeyAlbumArtist, "TPE2", "TP2" },
- { kKeyComposer, "TCOM", "TCM" },
- { kKeyGenre, "TCON", "TCO" },
- { kKeyTitle, "TIT2", "TT2" },
- { kKeyYear, "TYE", "TYER" },
- { kKeyAuthor, "TXT", "TEXT" },
- { kKeyCDTrackNumber, "TRK", "TRCK" },
- { kKeyDiscNumber, "TPA", "TPOS" },
- { kKeyCompilation, "TCP", "TCMP" },
+ { AMEDIAFORMAT_KEY_ALBUM, "TALB", "TAL" },
+ { AMEDIAFORMAT_KEY_ARTIST, "TPE1", "TP1" },
+ { AMEDIAFORMAT_KEY_ALBUMARTIST, "TPE2", "TP2" },
+ { AMEDIAFORMAT_KEY_COMPOSER, "TCOM", "TCM" },
+ { AMEDIAFORMAT_KEY_GENRE, "TCON", "TCO" },
+ { AMEDIAFORMAT_KEY_TITLE, "TIT2", "TT2" },
+ { AMEDIAFORMAT_KEY_YEAR, "TYE", "TYER" },
+ { AMEDIAFORMAT_KEY_AUTHOR, "TXT", "TEXT" },
+ { AMEDIAFORMAT_KEY_CDTRACKNUMBER, "TRK", "TRCK" },
+ { AMEDIAFORMAT_KEY_DISCNUMBER, "TPA", "TPOS" },
+ { AMEDIAFORMAT_KEY_COMPILATION, "TCP", "TCMP" },
};
static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
@@ -655,7 +658,7 @@
it->getString(&s);
delete it;
- meta.setCString(kMap[i].key, s);
+ AMediaFormat_setString(meta, kMap[i].key, s.string());
}
size_t dataSize;
@@ -663,21 +666,20 @@
const void *data = id3.getAlbumArt(&dataSize, &mime);
if (data) {
- meta.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
- meta.setCString(kKeyAlbumArtMIME, mime.string());
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_ALBUMART, data, dataSize);
}
- return OK;
+ return AMEDIA_OK;
}
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *meta) {
Mp3Meta *metaData = static_cast<Mp3Meta *>(meta);
- return wrap(new MP3Extractor(new DataSourceHelper(source), metaData));
+ return wrapV2(new MP3Extractor(new DataSourceHelper(source), metaData));
}
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
CDataSource *source, float *confidence, void **meta,
FreeMetaFunc *freeMeta) {
off64_t pos = 0;
@@ -714,11 +716,11 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
1, // version
"MP3 Extractor",
- { Sniff }
+ { .v2 = Sniff }
};
}
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 92e0665..22547e2 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -21,7 +21,7 @@
#include <utils/Errors.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -32,16 +32,16 @@
class String8;
struct Mp3Meta;
-class MP3Extractor : public MediaExtractorPluginHelper {
+class MP3Extractor : public MediaExtractorPluginHelperV2 {
public:
MP3Extractor(DataSourceHelper *source, Mp3Meta *meta);
~MP3Extractor();
virtual size_t countTracks();
- virtual MediaTrackHelper *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "MP3Extractor"; }
private:
@@ -49,7 +49,7 @@
DataSourceHelper *mDataSource;
off64_t mFirstFramePos;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
uint32_t mFixedHeader;
MP3Seeker *mSeeker;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e81e9b2..3a58aa6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -150,6 +150,8 @@
status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
status_t parseSampleEncryption(off64_t offset);
+ // returns -1 for invalid layer ID
+ int32_t parseHEVCLayerId(const uint8_t *data, size_t size);
struct TrackFragmentHeaderInfo {
enum Flags {
@@ -3608,7 +3610,6 @@
if (data) {
mFileMetaData.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
- mFileMetaData.setCString(kKeyAlbumArtMIME, mime.string());
}
}
}
@@ -4936,6 +4937,35 @@
return 0;
}
+int32_t MPEG4Source::parseHEVCLayerId(const uint8_t *data, size_t size) {
+ CHECK(data != nullptr && size >= (mNALLengthSize + 2));
+
+ // HEVC NAL-header (16-bit)
+ // 1 6 6 3
+ // |-|uuuuuu|------|iii|
+ // ^ ^
+ // NAL_type layer_id + 1
+ //
+ // Layer-id is non-zero only for Temporal Sub-layer Access pictures (TSA)
+ enum {
+ TSA_N = 2,
+ TSA_R = 3,
+ STSA_N = 4,
+ STSA_R = 5,
+ };
+
+ data += mNALLengthSize;
+ uint16_t nalHeader = data[0] << 8 | data[1];
+
+ uint16_t nalType = (nalHeader >> 9) & 0x3Fu;
+ if (nalType == TSA_N || nalType == TSA_R || nalType == STSA_N || nalType == STSA_R) {
+ int32_t layerIdPlusOne = nalHeader & 0x7u;
+ ALOGD_IF(layerIdPlusOne == 0, "got layerId 0 for TSA picture");
+ return layerIdPlusOne - 1;
+ }
+ return 0;
+}
+
status_t MPEG4Source::read(
MediaBufferBase **out, const ReadOptions *options) {
Mutex::Autolock autoLock(mLock);
@@ -5369,6 +5399,12 @@
uint32_t layerId = FindAVCLayerId(
(const uint8_t *)mBuffer->data(), mBuffer->range_length());
mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+ } else if (mIsHEVC) {
+ int32_t layerId = parseHEVCLayerId(
+ (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+ if (layerId >= 0) {
+ mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+ }
}
if (isSyncSample) {
@@ -5567,6 +5603,12 @@
uint32_t layerId = FindAVCLayerId(
(const uint8_t *)mBuffer->data(), mBuffer->range_length());
mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+ } else if (mIsHEVC) {
+ int32_t layerId = parseHEVCLayerId(
+ (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+ if (layerId >= 0) {
+ mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+ }
}
if (isSyncSample) {
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 7c6fc75..c6deb18 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -10,10 +10,12 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
"libstagefright_foundation",
+ "libstagefright_metadatautils",
"libutils",
"libvorbisidec",
],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 123ac91..a52ccb1 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -24,7 +24,6 @@
#include <utils/Vector.h>
#include <media/DataSourceBase.h>
#include <media/ExtractorUtils.h>
-#include <media/VorbisComment.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
@@ -34,6 +33,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
extern "C" {
@@ -47,15 +47,15 @@
namespace android {
-struct OggSource : public MediaTrackHelper {
+struct OggSource : public MediaTrackHelperV2 {
explicit OggSource(OggExtractor *extractor);
- virtual status_t getFormat(MetaDataBase &);
+ virtual media_status_t getFormat(AMediaFormat *);
- virtual status_t start();
- virtual status_t stop();
+ virtual media_status_t start();
+ virtual media_status_t stop();
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
@@ -77,20 +77,19 @@
int64_t seekPreRollUs);
virtual ~MyOggExtractor();
- status_t getFormat(MetaDataBase &) const;
+ media_status_t getFormat(AMediaFormat *) const;
// Returns an approximate bitrate in bits per second.
virtual uint64_t approxBitrate() const = 0;
status_t seekToTime(int64_t timeUs);
status_t seekToOffset(off64_t offset);
- virtual status_t readNextPacket(MediaBufferBase **buffer) = 0;
+ virtual media_status_t readNextPacket(MediaBufferBase **buffer) = 0;
status_t init();
- status_t getFileMetaData(MetaDataBase &meta) {
- meta = mFileMeta;
- return OK;
+ media_status_t getFileMetaData(AMediaFormat *meta) {
+ return AMediaFormat_copy(meta, mFileMeta);
}
protected:
@@ -129,8 +128,8 @@
vorbis_info mVi;
vorbis_comment mVc;
- MetaDataBase mMeta;
- MetaDataBase mFileMeta;
+ AMediaFormat *mMeta;
+ AMediaFormat *mFileMeta;
Vector<TOCEntry> mTableOfContents;
@@ -146,7 +145,7 @@
// 1 - bitstream identification header
// 3 - comment header
// 5 - codec setup header (Vorbis only)
- virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
+ virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
// Read the next ogg packet from the underlying data source; optionally
// calculate the timestamp for the output packet whilst pretending
@@ -154,7 +153,7 @@
//
// *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated;
// clients are responsible for releasing the original buffer.
- status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
+ media_status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
int32_t getPacketBlockSize(MediaBufferBase *buffer);
@@ -178,7 +177,7 @@
virtual uint64_t approxBitrate() const;
- virtual status_t readNextPacket(MediaBufferBase **buffer) {
+ virtual media_status_t readNextPacket(MediaBufferBase **buffer) {
return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true);
}
@@ -190,7 +189,7 @@
return granulePos * 1000000ll / mVi.rate;
}
- virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
+ virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
};
struct MyOpusExtractor : public MyOggExtractor {
@@ -208,15 +207,15 @@
return 0;
}
- virtual status_t readNextPacket(MediaBufferBase **buffer);
+ virtual media_status_t readNextPacket(MediaBufferBase **buffer);
protected:
virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const;
- virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
+ virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
private:
- status_t verifyOpusHeader(MediaBufferBase *buffer);
- status_t verifyOpusComments(MediaBufferBase *buffer);
+ media_status_t verifyOpusHeader(MediaBufferBase *buffer);
+ media_status_t verifyOpusComments(MediaBufferBase *buffer);
uint32_t getNumSamplesInPacket(MediaBufferBase *buffer) const;
uint8_t mChannelCount;
@@ -237,27 +236,27 @@
}
}
-status_t OggSource::getFormat(MetaDataBase &meta) {
+media_status_t OggSource::getFormat(AMediaFormat *meta) {
return mExtractor->mImpl->getFormat(meta);
}
-status_t OggSource::start() {
+media_status_t OggSource::start() {
if (mStarted) {
- return INVALID_OPERATION;
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t OggSource::stop() {
+media_status_t OggSource::stop() {
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t OggSource::read(
+media_status_t OggSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@@ -266,14 +265,14 @@
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
if (err != OK) {
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
}
MediaBufferBase *packet;
- status_t err = mExtractor->mImpl->readNextPacket(&packet);
+ media_status_t err = mExtractor->mImpl->readNextPacket(&packet);
- if (err != OK) {
+ if (err != AMEDIA_OK) {
return err;
}
@@ -290,7 +289,7 @@
*out = packet;
- return OK;
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
@@ -316,16 +315,19 @@
vorbis_info_init(&mVi);
vorbis_comment_init(&mVc);
+ mMeta = AMediaFormat_new();
+ mFileMeta = AMediaFormat_new();
}
MyOggExtractor::~MyOggExtractor() {
+ AMediaFormat_delete(mFileMeta);
+ AMediaFormat_delete(mMeta);
vorbis_comment_clear(&mVc);
vorbis_info_clear(&mVi);
}
-status_t MyOggExtractor::getFormat(MetaDataBase &meta) const {
- meta = mMeta;
- return OK;
+media_status_t MyOggExtractor::getFormat(AMediaFormat *meta) const {
+ return AMediaFormat_copy(meta, mMeta);
}
status_t MyOggExtractor::findNextPage(
@@ -505,27 +507,27 @@
if (n < 0) {
return n;
} else if (n == 0) {
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
} else {
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
}
}
if (memcmp(header, "OggS", 4)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
if (header[4] != 0) {
// Wrong version.
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
page->mFlags = header[5];
if (page->mFlags & ~7) {
// Only bits 0-2 are defined in version 0.
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
page->mGranulePosition = U64LE_AT(&header[6]);
@@ -542,7 +544,7 @@
if (mSource->readAt(
offset + sizeof(header), page->mLace, page->mNumSegments)
< (ssize_t)page->mNumSegments) {
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
}
size_t totalSize = 0;;
@@ -565,7 +567,7 @@
return sizeof(header) + page->mNumSegments + totalSize;
}
-status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
+media_status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
// The first sample might not start at time 0; find out where by subtracting
// the number of samples on the first page from the granule position
@@ -575,12 +577,12 @@
uint32_t numSamples = 0;
uint64_t curGranulePosition = 0;
while (true) {
- status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
- if (err != OK && err != ERROR_END_OF_STREAM) {
+ media_status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
+ if (err != AMEDIA_OK && err != AMEDIA_ERROR_END_OF_STREAM) {
return err;
}
// First two pages are header pages.
- if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
+ if (err == AMEDIA_ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
if (mBuf != NULL) {
mBuf->release();
mBuf = NULL;
@@ -601,8 +603,8 @@
seekToOffset(0);
}
- status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
- if (err != OK) {
+ media_status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
+ if (err != AMEDIA_OK) {
return err;
}
@@ -623,7 +625,7 @@
uint32_t frames = getNumSamplesInPacket(*out);
mCurGranulePosition += frames;
- return OK;
+ return AMEDIA_OK;
}
uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
@@ -672,7 +674,7 @@
return numSamples;
}
-status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
+media_status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
*out = NULL;
MediaBufferBase *buffer = NULL;
@@ -709,7 +711,7 @@
buffer->release();
}
ALOGE("b/36592202");
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
if (tmp == NULL) {
@@ -717,7 +719,7 @@
buffer->release();
}
ALOGE("b/36592202");
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
if (buffer != NULL) {
memcpy(tmp->data(), buffer->data(), buffer->range_length());
@@ -737,7 +739,7 @@
buffer->release();
ALOGV("failed to read %zu bytes at %#016llx, got %zd bytes",
packetSize, (long long)dataOffset, n);
- return ERROR_IO;
+ return AMEDIA_ERROR_IO;
}
buffer->set_range(0, fullSize);
@@ -774,7 +776,7 @@
}
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
// fall through, the buffer now contains the start of the packet.
@@ -793,7 +795,7 @@
ALOGV("readPage returned %zd", n);
- return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
+ return n < 0 ? (media_status_t) n : AMEDIA_ERROR_END_OF_STREAM;
}
// Prevent a harmless unsigned integer overflow by clamping to 0
@@ -825,27 +827,27 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
}
}
}
status_t MyOggExtractor::init() {
- mMeta.setCString(kKeyMIMEType, mMimeType);
+ AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
- status_t err;
+ media_status_t err;
MediaBufferBase *packet;
for (size_t i = 0; i < mNumHeaders; ++i) {
// ignore timestamp for configuration packets
- if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) {
+ if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != AMEDIA_OK) {
return err;
}
ALOGV("read packet of size %zu\n", packet->range_length());
err = verifyHeader(packet, /* type = */ i * 2 + 1);
packet->release();
packet = NULL;
- if (err != OK) {
+ if (err != AMEDIA_OK) {
return err;
}
}
@@ -865,12 +867,12 @@
int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
- mMeta.setInt64(kKeyDuration, durationUs);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
buildTableOfContents();
}
- return OK;
+ return AMEDIA_OK;
}
void MyOggExtractor::buildTableOfContents() {
@@ -952,7 +954,7 @@
return pcmSamplePosition * 1000000ll / kOpusSampleRate;
}
-status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
+media_status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
switch (type) {
// there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean
// header and comments such that we can share code with MyVorbisExtractor.
@@ -961,11 +963,11 @@
case 3:
return verifyOpusComments(buffer);
default:
- return INVALID_OPERATION;
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
}
-status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
+media_status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
const size_t kOpusHeaderSize = 19;
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
@@ -975,29 +977,31 @@
if (size < kOpusHeaderSize
|| memcmp(data, "OpusHead", 8)
|| /* version = */ data[8] != 1) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
mChannelCount = data[9];
mCodecDelay = U16LE_AT(&data[10]);
- mMeta.setData(kKeyOpusHeader, 0, data, size);
- mMeta.setInt32(kKeySampleRate, kOpusSampleRate);
- mMeta.setInt32(kKeyChannelCount, mChannelCount);
- mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
- mMeta.setInt64(kKeyOpusCodecDelay /* ns */,
- mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
+ // kKeyOpusHeader is csd-0
+ AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
+ int64_t codecdelay = mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate;
+ AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, &codecdelay, sizeof(codecdelay));
+ int64_t preroll = kOpusSeekPreRollUs * 1000 /* = 80 ms*/;
+ AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_2, &preroll, sizeof(preroll));
- return OK;
+ return AMEDIA_OK;
}
-status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
+media_status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
// add artificial framing bit so we can reuse _vorbis_unpack_comment
int32_t commentSize = buffer->range_length() + 1;
auto tmp = heapbuffer<uint8_t>(commentSize);
uint8_t *commentData = tmp.get();
if (commentData == nullptr) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
memcpy(commentData,
@@ -1026,14 +1030,14 @@
for (int i = 0; i < headerLen; ++i) {
char chr = oggpack_read(&bits, 8);
if (chr != OpusTags[i]) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
}
int32_t vendorLen = oggpack_read(&bits, 32);
framingBitOffset += 4;
if (vendorLen < 0 || vendorLen > commentSize - 8) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
// skip vendor string
framingBitOffset += vendorLen;
@@ -1044,13 +1048,13 @@
int32_t n = oggpack_read(&bits, 32);
framingBitOffset += 4;
if (n < 0 || n > ((commentSize - oggpack_bytes(&bits)) >> 2)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
for (int i = 0; i < n; ++i) {
int32_t len = oggpack_read(&bits, 32);
framingBitOffset += 4;
if (len < 0 || len > (commentSize - oggpack_bytes(&bits))) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
framingBitOffset += len;
for (int j = 0; j < len; ++j) {
@@ -1058,7 +1062,7 @@
}
}
if (framingBitOffset < 0 || framingBitOffset >= commentSize) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
commentData[framingBitOffset] = 1;
@@ -1075,14 +1079,14 @@
oggpack_readinit(&bits, &ref);
int err = _vorbis_unpack_comment(&mVc, &bits);
if (0 != err) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
parseFileMetaData();
- return OK;
+ return AMEDIA_OK;
}
-status_t MyVorbisExtractor::verifyHeader(
+media_status_t MyVorbisExtractor::verifyHeader(
MediaBufferBase *buffer, uint8_t type) {
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
@@ -1090,7 +1094,7 @@
size_t size = buffer->range_length();
if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
ogg_buffer buf;
@@ -1109,7 +1113,7 @@
oggpack_readinit(&bits, &ref);
if (oggpack_read(&bits, 8) != type) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
for (size_t i = 0; i < 6; ++i) {
oggpack_read(&bits, 8); // skip 'vorbis'
@@ -1119,13 +1123,13 @@
case 1:
{
if (0 != _vorbis_unpack_info(&mVi, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
- mMeta.setData(kKeyVorbisInfo, 0, data, size);
- mMeta.setInt32(kKeySampleRate, mVi.rate);
- mMeta.setInt32(kKeyChannelCount, mVi.channels);
- mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal);
+ AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mVi.rate);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mVi.channels);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, mVi.bitrate_nominal);
ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@@ -1140,7 +1144,7 @@
if (mSource->getSize(&size) == OK) {
uint64_t bps = approxBitrate();
if (bps != 0) {
- mMeta.setInt64(kKeyDuration, size * 8000000ll / bps);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, size * 8000000ll / bps);
}
}
break;
@@ -1149,7 +1153,7 @@
case 3:
{
if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
parseFileMetaData();
@@ -1159,15 +1163,15 @@
case 5:
{
if (0 != _vorbis_unpack_books(&mVi, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
- mMeta.setData(kKeyVorbisBooks, 0, data, size);
+ AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
break;
}
}
- return OK;
+ return AMEDIA_OK;
}
uint64_t MyVorbisExtractor::approxBitrate() const {
@@ -1180,12 +1184,12 @@
void MyOggExtractor::parseFileMetaData() {
- mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+ AMediaFormat_setString(mFileMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_OGG);
for (int i = 0; i < mVc.comments; ++i) {
const char *comment = mVc.user_comments[i];
size_t commentLength = mVc.comment_lengths[i];
- parseVorbisComment(&mFileMeta, comment, commentLength);
+ parseVorbisComment(mFileMeta, comment, commentLength);
//ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
}
}
@@ -1227,7 +1231,7 @@
return mInitCheck != OK ? 0 : 1;
}
-MediaTrackHelper *OggExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *OggExtractor::getTrack(size_t index) {
if (index >= 1) {
return NULL;
}
@@ -1235,27 +1239,27 @@
return new OggSource(this);
}
-status_t OggExtractor::getTrackMetaData(
- MetaDataBase &meta,
+media_status_t OggExtractor::getTrackMetaData(
+ AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (index >= 1) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
return mImpl->getFormat(meta);
}
-status_t OggExtractor::getMetaData(MetaDataBase &meta) {
+media_status_t OggExtractor::getMetaData(AMediaFormat *meta) {
return mImpl->getFileMetaData(meta);
}
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *) {
- return wrap(new OggExtractor(new DataSourceHelper(source)));
+ return wrapV2(new OggExtractor(new DataSourceHelper(source)));
}
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
CDataSource *source,
float *confidence,
void **,
@@ -1276,11 +1280,11 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
1, // version
"Ogg Extractor",
- { Sniff }
+ { .v2 = Sniff }
};
}
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index c70f832..cd674f3 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -30,14 +31,14 @@
struct MyOggExtractor;
struct OggSource;
-struct OggExtractor : public MediaExtractorPluginHelper {
+struct OggExtractor : public MediaExtractorPluginHelperV2 {
explicit OggExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrackHelper *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "OggExtractor"; }
protected:
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index cc1a501..9a329f1 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -62,11 +62,11 @@
int32_t bitsPerSample,
off64_t offset, size_t size);
- virtual status_t start();
- virtual status_t stop();
- virtual status_t getFormat(AMediaFormat *meta);
+ virtual media_status_t start();
+ virtual media_status_t stop();
+ virtual media_status_t getFormat(AMediaFormat *meta);
- virtual status_t read(
+ virtual media_status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual bool supportNonblockingRead() { return true; }
@@ -106,13 +106,13 @@
AMediaFormat_delete(mTrackMeta);
}
-status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
+media_status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
AMediaFormat_clear(meta);
if (mInitCheck == OK) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_WAV);
}
- return OK;
+ return AMEDIA_OK;
}
size_t WAVExtractor::countTracks() {
@@ -129,15 +129,14 @@
mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
}
-status_t WAVExtractor::getTrackMetaData(
+media_status_t WAVExtractor::getTrackMetaData(
AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index > 0) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
- AMediaFormat_copy(meta, mTrackMeta);
- return OK;
+ return AMediaFormat_copy(meta, mTrackMeta);
}
status_t WAVExtractor::init() {
@@ -187,7 +186,7 @@
&& mWaveFormat != WAVE_FORMAT_MULAW
&& mWaveFormat != WAVE_FORMAT_MSGSM
&& mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
uint8_t fmtSize = 16;
@@ -202,7 +201,7 @@
if (mNumChannels < 1 || mNumChannels > 8) {
ALOGE("Unsupported number of channels (%d)", mNumChannels);
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
@@ -226,7 +225,7 @@
if (validBitsPerSample != 0) {
ALOGE("validBits(%d) != bitsPerSample(%d) are not supported",
validBitsPerSample, mBitsPerSample);
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
} else {
// we only support valitBitsPerSample == bitsPerSample but some WAV_EXT
// writers don't correctly set the valid bits value, and leave it at 0.
@@ -324,12 +323,12 @@
size_t bytesPerSample = mBitsPerSample >> 3;
if (!bytesPerSample || !mNumChannels)
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
size_t num_samples = mDataSize / (mNumChannels * bytesPerSample);
if (!mSampleRate)
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
durationUs =
1000000LL * num_samples / mSampleRate;
@@ -377,7 +376,7 @@
}
}
-status_t WAVSource::start() {
+media_status_t WAVSource::start() {
ALOGV("WAVSource::start");
CHECK(!mStarted);
@@ -394,10 +393,10 @@
mStarted = true;
- return OK;
+ return AMEDIA_OK;
}
-status_t WAVSource::stop() {
+media_status_t WAVSource::stop() {
ALOGV("WAVSource::stop");
CHECK(mStarted);
@@ -407,22 +406,21 @@
mStarted = false;
- return OK;
+ return AMEDIA_OK;
}
-status_t WAVSource::getFormat(AMediaFormat *meta) {
+media_status_t WAVSource::getFormat(AMediaFormat *meta) {
ALOGV("WAVSource::getFormat");
- AMediaFormat_copy(meta, mMeta);
- return OK;
+ return AMediaFormat_copy(meta, mMeta);
}
-status_t WAVSource::read(
+media_status_t WAVSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
- return WOULD_BLOCK;
+ return AMEDIA_ERROR_WOULD_BLOCK;
}
int64_t seekTimeUs;
@@ -447,7 +445,7 @@
MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
// make sure that maxBytesToRead is multiple of 3, in 24-bit case
@@ -484,7 +482,7 @@
buffer->release();
buffer = NULL;
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
buffer->set_range(0, n);
@@ -542,7 +540,7 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 2822e80..ce34881 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -35,9 +35,9 @@
virtual size_t countTracks();
virtual MediaTrackHelperV2 *getTrack(size_t index);
- virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+ virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(AMediaFormat *meta);
+ virtual media_status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "WAVExtractor"; }
virtual ~WAVExtractor();
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ef272b0..319467e 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -19,6 +19,18 @@
}
cc_test {
+ name: "test_clock_model",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_clock_model.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libaudioutils",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
name: "test_block_adapter",
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_block_adapter.cpp"],
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
new file mode 100644
index 0000000..3c09025
--- /dev/null
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+// Unit tests for Isochronous Clock Model
+
+#include <math.h>
+#include <stdlib.h>
+
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/clock.h>
+#include <client/IsochronousClockModel.h>
+#include <gtest/gtest.h>
+
+using namespace aaudio;
+
+// We can use arbitrary values here because we are not opening a real audio stream.
+#define SAMPLE_RATE 48000
+#define HW_FRAMES_PER_BURST 48
+#define NANOS_PER_BURST (NANOS_PER_SECOND * HW_FRAMES_PER_BURST / SAMPLE_RATE)
+
+class ClockModelTestFixture: public ::testing::Test {
+public:
+ ClockModelTestFixture() {
+ }
+
+ void SetUp() {
+ model.setSampleRate(SAMPLE_RATE);
+ model.setFramesPerBurst(HW_FRAMES_PER_BURST);
+ }
+
+ void TearDown() {
+
+ }
+
+ ~ClockModelTestFixture() {
+ // cleanup any pending stuff, but no exceptions allowed
+ }
+
+ IsochronousClockModel model;
+};
+
+// Check default setup.
+TEST_F(ClockModelTestFixture, clock_setup) {
+ ASSERT_EQ(SAMPLE_RATE, model.getSampleRate());
+ ASSERT_EQ(HW_FRAMES_PER_BURST, model.getFramesPerBurst());
+}
+
+// Test delta calculations.
+TEST_F(ClockModelTestFixture, clock_deltas) {
+ int64_t position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND);
+ ASSERT_EQ(SAMPLE_RATE, position);
+
+ // Deltas are not quantized.
+ // Compare time to the equivalent position in frames.
+ constexpr int64_t kNanosPerBurst = HW_FRAMES_PER_BURST * NANOS_PER_SECOND / SAMPLE_RATE;
+ position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND + (kNanosPerBurst / 2));
+ ASSERT_EQ(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2), position);
+
+ int64_t time = model.convertDeltaPositionToTime(SAMPLE_RATE);
+ ASSERT_EQ(NANOS_PER_SECOND, time);
+
+ // Compare position in frames to the equivalent time.
+ time = model.convertDeltaPositionToTime(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2));
+ ASSERT_EQ(NANOS_PER_SECOND + (kNanosPerBurst / 2), time);
+}
+
+// start() should force the internal markers
+TEST_F(ClockModelTestFixture, clock_start) {
+ const int64_t startTime = 100000;
+ model.start(startTime);
+
+ int64_t position = model.convertTimeToPosition(startTime);
+ EXPECT_EQ(0, position);
+
+ int64_t time = model.convertPositionToTime(position);
+ EXPECT_EQ(startTime, time);
+
+ time = startTime + (500 * NANOS_PER_MICROSECOND);
+ position = model.convertTimeToPosition(time);
+ EXPECT_EQ(0, position);
+}
+
+// timestamps moves the window if outside the bounds
+// TODO test nudging the window
+TEST_F(ClockModelTestFixture, clock_timestamp) {
+ const int64_t startTime = 100000000;
+ model.start(startTime);
+
+ const int64_t position = HW_FRAMES_PER_BURST; // hardware
+ int64_t markerTime = startTime + NANOS_PER_MILLISECOND + (200 * NANOS_PER_MICROSECOND);
+
+ // Should set marker.
+ model.processTimestamp(position, markerTime);
+ EXPECT_EQ(position, model.convertTimeToPosition(markerTime));
+
+ // convertTimeToPosition rounds down
+ EXPECT_EQ(position, model.convertTimeToPosition(markerTime + (73 * NANOS_PER_MICROSECOND)));
+
+ // convertPositionToTime rounds up
+ EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 34c5428..038c854 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1300,10 +1300,7 @@
mNewPosition = position + mUpdatePeriod;
status_t result = createRecord_l(position, mOpPackageName);
- if (result != NO_ERROR) {
- ALOGW("%s(%d): createRecord_l failed, do not retry", __func__, mId);
- retries = 0;
- } else {
+ if (result == NO_ERROR) {
if (mActive) {
// callback thread or sync event hasn't changed
// FIXME this fails if we have a new AudioFlinger instance
@@ -1316,13 +1313,15 @@
if (result != NO_ERROR) {
ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
if (--retries > 0) {
+ // leave time for an eventual race condition to clear before retrying
+ usleep(500000);
goto retry;
}
- }
-
- if (result != NO_ERROR) {
- ALOGW("%s(%d): failed status %d", __func__, mId, result);
- mActive = false;
+ // if no retries left, set invalid bit to force restoring at next occasion
+ // and avoid inconsistent active state on client and server sides
+ if (mCblk != nullptr) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
return result;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e77abc6..8b35a85 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -399,9 +399,10 @@
}
break;
case TRANSFER_CALLBACK:
+ case TRANSFER_SYNC_NOTIF_CALLBACK:
if (cbf == NULL || sharedBuffer != 0) {
- ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0",
- __func__);
+ ALOGE("%s(): Transfer type %s but cbf == NULL || sharedBuffer != 0",
+ convertTransferToText(transferType), __func__);
status = BAD_VALUE;
goto exit;
}
@@ -1406,6 +1407,7 @@
MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
MEDIA_CASE_ENUM(TRANSFER_SYNC);
MEDIA_CASE_ENUM(TRANSFER_SHARED);
+ MEDIA_CASE_ENUM(TRANSFER_SYNC_NOTIF_CALLBACK);
default:
return "UNRECOGNIZED";
}
@@ -1438,7 +1440,8 @@
// use case 3: obtain/release mode
(mTransfer == TRANSFER_OBTAIN) ||
// use case 4: synchronous write
- ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+ ((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
+ && mThreadCanCallJava);
bool fastAllowed = sharedBuffer || transferAllowed;
if (!fastAllowed) {
@@ -1795,7 +1798,7 @@
ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
{
- if (mTransfer != TRANSFER_SYNC) {
+ if (mTransfer != TRANSFER_SYNC && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
return INVALID_OPERATION;
}
@@ -1846,7 +1849,17 @@
if (written > 0) {
mFramesWritten += written / mFrameSize;
+
+ if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+ const sp<AudioTrackThread> t = mAudioTrackThread;
+ if (t != 0) {
+ // causes wake up of the playback thread, that will callback the client for
+ // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer()
+ t->wake();
+ }
+ }
}
+
return written;
}
@@ -2100,8 +2113,8 @@
if (ns < 0) ns = 0;
}
- // If not supplying data by EVENT_MORE_DATA, then we're done
- if (mTransfer != TRANSFER_CALLBACK) {
+ // If not supplying data by EVENT_MORE_DATA or EVENT_CAN_WRITE_MORE_DATA, then we're done
+ if (mTransfer != TRANSFER_CALLBACK && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
return ns;
}
@@ -2163,7 +2176,13 @@
}
size_t reqSize = audioBuffer.size;
- mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+ if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+ // when notifying client it can write more data, pass the total size that can be
+ // written in the next write() call, since it's not passed through the callback
+ audioBuffer.size += nonContig;
+ }
+ mCbf(mTransfer == TRANSFER_CALLBACK ? EVENT_MORE_DATA : EVENT_CAN_WRITE_MORE_DATA,
+ mUserData, &audioBuffer);
size_t writtenSize = audioBuffer.size;
// Sanity check on returned size
@@ -2174,6 +2193,14 @@
}
if (writtenSize == 0) {
+ if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+ // The callback EVENT_CAN_WRITE_MORE_DATA was processed in the JNI of
+ // android.media.AudioTrack. The JNI is not using the callback to provide data,
+ // it only signals to the Java client that it can provide more data, which
+ // this track is read to accept now.
+ // The playback thread will be awaken at the next ::write()
+ return NS_WHENEVER;
+ }
// The callback is done filling buffers
// Keep this thread going to handle timed events and
// still try to get more data in intervals of WAIT_PERIOD_MS
@@ -2308,10 +2335,7 @@
// If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
status_t result = createTrack_l();
- if (result != NO_ERROR) {
- ALOGW("%s(%d): createTrack_l failed, do not retry", __func__, mId);
- retries = 0;
- } else {
+ if (result == NO_ERROR) {
// take the frames that will be lost by track recreation into account in saved position
// For streaming tracks, this is the amount we obtained from the user/client
// (not the number actually consumed at the server - those are already lost).
@@ -2358,12 +2382,16 @@
if (result != NO_ERROR) {
ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
if (--retries > 0) {
+ // leave time for an eventual race condition to clear before retrying
+ usleep(500000);
goto retry;
}
- mState = STATE_STOPPED;
- mReleased = 0;
+ // if no retries left, set invalid bit to force restoring at next occasion
+ // and avoid inconsistent active state on client and server sides
+ if (mCblk != nullptr) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
-
return result;
}
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c5105af..4b84fd1 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -74,6 +74,8 @@
// in the mapping from frame position to presentation time.
// See AudioTimestamp for the information included with event.
#endif
+ EVENT_CAN_WRITE_MORE_DATA = 9,// Notification that more data can be given by write()
+ // This event only occurs for TRANSFER_SYNC_NOTIF_CALLBACK.
};
/* Client should declare a Buffer and pass the address to obtainBuffer()
@@ -153,6 +155,7 @@
TRANSFER_OBTAIN, // call obtainBuffer() and releaseBuffer()
TRANSFER_SYNC, // synchronous write()
TRANSFER_SHARED, // shared memory
+ TRANSFER_SYNC_NOTIF_CALLBACK, // synchronous write(), notif EVENT_CAN_WRITE_MORE_DATA
};
/* Constructs an uninitialized AudioTrack. No connection with
@@ -295,6 +298,8 @@
* Parameters not listed in the AudioTrack constructors above:
*
* threadCanCallJava: Whether callbacks are made from an attached thread and thus can call JNI.
+ * Only set to true when AudioTrack object is used for a java android.media.AudioTrack
+ * in its JNI code.
*
* Internal state post condition:
* (mStreamType == AUDIO_STREAM_DEFAULT) implies this AudioTrack has valid attributes
diff --git a/media/libaudioprocessing/tests/Android.mk b/media/libaudioprocessing/tests/Android.mk
index 8e081a3..31ffbdc 100644
--- a/media/libaudioprocessing/tests/Android.mk
+++ b/media/libaudioprocessing/tests/Android.mk
@@ -20,6 +20,8 @@
LOCAL_SRC_FILES := \
resampler_tests.cpp
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
LOCAL_MODULE := resampler_tests
LOCAL_MODULE_TAGS := tests
@@ -49,6 +51,8 @@
liblog \
libutils \
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
LOCAL_MODULE := test-mixer
LOCAL_MODULE_TAGS := optional
diff --git a/media/libaudioprocessing/tests/test_utils.h b/media/libaudioprocessing/tests/test_utils.h
index b61a929..21f5862 100644
--- a/media/libaudioprocessing/tests/test_utils.h
+++ b/media/libaudioprocessing/tests/test_utils.h
@@ -23,6 +23,7 @@
#include <log/log.h>
+#include <android-base/macros.h>
#include <audio_utils/sndfile.h>
#ifndef ARRAY_SIZE
@@ -77,14 +78,14 @@
}
return numValues;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case ',':
if (hadDigit) {
hadDigit = false;
numValues++;
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
default:
return -1;
}
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 686ec4c..d558169 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1751,15 +1751,14 @@
// *(int16_t *)pValue);
break;
case REVERB_PARAM_DENSITY:
- *(uint16_t *)pValue = 0;
*(int16_t *)pValue = ReverbGetDensity(pContext);
//ALOGV("\tReverb_getParameter() REVERB_PARAM_DENSITY Value is %d",
// *(uint32_t *)pValue);
break;
case REVERB_PARAM_REFLECTIONS_LEVEL:
*(uint16_t *)pValue = 0;
+ break;
case REVERB_PARAM_REFLECTIONS_DELAY:
- *(uint32_t *)pValue = 0;
case REVERB_PARAM_REVERB_DELAY:
*(uint32_t *)pValue = 0;
break;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index b914f4b..50c33c6 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -698,6 +698,7 @@
case PREPROC_EFFECT_STATE_ACTIVE:
effect->ops->disable(effect);
Session_SetProcEnabled(effect->session, effect->procId, false);
+ break;
case PREPROC_EFFECT_STATE_CONFIG:
case PREPROC_EFFECT_STATE_CREATED:
case PREPROC_EFFECT_STATE_INIT:
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index bb87b10..25d28ff 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -128,6 +128,10 @@
"libsonivox",
],
+ header_libs: [
+ "media_ndk_headers",
+ ],
+
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
@@ -149,7 +153,7 @@
filegroup {
name: "mediaupdateservice_aidl",
srcs: [
- "aidl/android/media/IMediaExtractorUpdateService.aidl",
+ "aidl/android/media/IMediaUpdateService.aidl",
],
}
@@ -193,6 +197,7 @@
"Visualizer.cpp",
"StringArray.cpp",
"NdkMediaFormatPriv.cpp",
+ "NdkMediaErrorPriv.cpp",
],
aidl: {
@@ -202,10 +207,12 @@
header_libs: [
"libstagefright_headers",
+ "media_ndk_headers",
],
export_header_lib_headers: [
"libstagefright_headers",
+ "media_ndk_headers",
],
shared_libs: [
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index aca7ad9..bd18a40 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -23,6 +23,7 @@
#include <media/IMediaCodecList.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
+#include <media/IMediaPlayer.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
#include <media/IRemoteDisplay.h>
diff --git a/media/ndk/NdkMediaError.cpp b/media/libmedia/NdkMediaErrorPriv.cpp
similarity index 71%
rename from media/ndk/NdkMediaError.cpp
rename to media/libmedia/NdkMediaErrorPriv.cpp
index 2facd8c..ba3b919 100644
--- a/media/ndk/NdkMediaError.cpp
+++ b/media/libmedia/NdkMediaErrorPriv.cpp
@@ -29,6 +29,12 @@
return AMEDIA_ERROR_END_OF_STREAM;
} else if (err == ERROR_IO) {
return AMEDIA_ERROR_IO;
+ } else if (err == ERROR_MALFORMED) {
+ return AMEDIA_ERROR_MALFORMED;
+ } else if (err == INVALID_OPERATION) {
+ return AMEDIA_ERROR_INVALID_OPERATION;
+ } else if (err == UNKNOWN_ERROR) {
+ return AMEDIA_ERROR_UNKNOWN;
}
ALOGE("sf error code: %d", err);
@@ -43,6 +49,14 @@
return ERROR_END_OF_STREAM;
} else if (err == AMEDIA_ERROR_IO) {
return ERROR_IO;
+ } else if (err == AMEDIA_ERROR_WOULD_BLOCK) {
+ return WOULD_BLOCK;
+ } else if (err == AMEDIA_ERROR_MALFORMED) {
+ return ERROR_MALFORMED;
+ } else if (err == AMEDIA_ERROR_INVALID_OPERATION) {
+ return INVALID_OPERATION;
+ } else if (err == AMEDIA_ERROR_UNKNOWN) {
+ return UNKNOWN_ERROR;
}
ALOGE("ndk error code: %d", err);
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 7d67262..9e09c7e 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1244,37 +1244,15 @@
return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
}
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
- DataSource *source = static_cast<DataSource *>(userdata);
- off64_t size = -1;
- source->getSize(&size);
- return size;
-}
-
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
- DataSource *source = static_cast<DataSource *>(userdata);
- return source->readAt(offset, buf, size);
-}
-
-void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
- DataSource *source = static_cast<DataSource *>(userdata);
- source->close();
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
- : mDataSource(dataSource),
- mAMediaDataSource(AMediaDataSource_new()) {
- ALOGV("setDataSource (source: %p)", dataSource.get());
- AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
- AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
- AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
- AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
+ : mAMediaDataSource(aDataSource) {
}
AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
if (mAMediaDataSource == NULL) {
return;
}
+ AMediaDataSource_close(mAMediaDataSource);
AMediaDataSource_delete(mAMediaDataSource);
mAMediaDataSource = NULL;
}
@@ -1283,4 +1261,8 @@
return mAMediaDataSource;
}
+void AMediaDataSourceWrapper::close() {
+ AMediaDataSource_close(mAMediaDataSource);
+}
+
} // namespace android
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
similarity index 84%
rename from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
rename to media/libmedia/aidl/android/media/IMediaUpdateService.aidl
index 57b1bc9..4777969 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
@@ -17,9 +17,9 @@
package android.media;
/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
+ * Service to reload media component plugins when update package is installed/uninstalled.
* @hide
*/
-interface IMediaExtractorUpdateService {
+interface IMediaUpdateService {
void loadPlugins(@utf8InCpp String apkPath);
}
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
index c190261..4336767 100644
--- a/media/libmedia/include/media/DataSourceDesc.h
+++ b/media/libmedia/include/media/DataSourceDesc.h
@@ -30,6 +30,11 @@
// A binder interface for implementing a stagefright DataSource remotely.
struct DataSourceDesc : public RefBase {
public:
+ // intentionally less than INT64_MAX
+ // keep consistent with JAVA code
+ static const int64_t kMaxTimeMs = 0x7ffffffffffffffll / 1000;
+ static const int64_t kMaxTimeUs = kMaxTimeMs * 1000;
+
enum {
/* No data source has been set yet */
TYPE_NONE = 0,
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index 217de14..f2e2060 100644
--- a/media/libmedia/include/media/IMediaPlayerService.h
+++ b/media/libmedia/include/media/IMediaPlayerService.h
@@ -26,11 +26,11 @@
#include <system/audio.h>
#include <media/IMediaPlayerClient.h>
-#include <media/IMediaPlayer.h>
#include <media/IMediaMetadataRetriever.h>
namespace android {
+class IMediaPlayer;
class IMediaCodecList;
struct IMediaHTTPService;
class IMediaRecorder;
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 191665a..b3b0688 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -278,6 +278,30 @@
DISALLOW_EVIL_CONSTRUCTORS(AMediaCodecWrapper);
};
+struct AMediaDataSourceWrapper : public RefBase {
+
+ AMediaDataSourceWrapper(AMediaDataSource*);
+ AMediaDataSourceWrapper(int fd, int64_t offset, int64_t length);
+
+ AMediaDataSource *getAMediaDataSource();
+ int getFd() { return mFd; }
+ int64_t getOffset() { return mOffset; }
+ int64_t getLength() { return mLength; }
+
+ void close();
+
+protected:
+ virtual ~AMediaDataSourceWrapper();
+
+private:
+ AMediaDataSource *mAMediaDataSource;
+ int mFd;
+ int64_t mOffset;
+ int64_t mLength;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
struct AMediaExtractorWrapper : public RefBase {
AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor);
@@ -337,31 +361,6 @@
DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
};
-struct AMediaDataSourceWrapper : public RefBase {
-
- static status_t translate_error(media_status_t err);
-
- static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
-
- static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
-
- static void AMediaDataSourceWrapper_close(void *userdata);
-
- AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
-
- AMediaDataSource *getAMediaDataSource();
-
-protected:
- virtual ~AMediaDataSourceWrapper();
-
-private:
- sp<DataSource> mDataSource;
-
- AMediaDataSource *mAMediaDataSource;
-
- DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
-};
-
} // namespace android
#endif // NDK_WRAPPER_H_
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index cdef637..1e5fa07 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -68,6 +68,9 @@
METADATA_KEY_VIDEO_FRAME_COUNT = 32,
METADATA_KEY_EXIF_OFFSET = 33,
METADATA_KEY_EXIF_LENGTH = 34,
+ METADATA_KEY_COLOR_STANDARD = 35,
+ METADATA_KEY_COLOR_TRANSFER = 36,
+ METADATA_KEY_COLOR_RANGE = 37,
// Add more here...
};
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index cf7d74f..0871d60 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -22,6 +22,14 @@
"liblog",
],
+ header_libs: [
+ "media_ndk_headers",
+ ],
+
+ export_header_lib_headers: [
+ "media_ndk_headers",
+ ],
+
srcs: [
"DataSourceBase.cpp",
"MediaBuffer.cpp",
@@ -30,7 +38,6 @@
"MediaSource.cpp",
"MetaData.cpp",
"MetaDataBase.cpp",
- "VorbisComment.cpp",
],
clang: true,
diff --git a/media/libmediaextractor/VorbisComment.cpp b/media/libmediaextractor/VorbisComment.cpp
deleted file mode 100644
index fabaf51..0000000
--- a/media/libmediaextractor/VorbisComment.cpp
+++ /dev/null
@@ -1,153 +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 "VorbisComment"
-#include <utils/Log.h>
-
-#include "media/VorbisComment.h"
-
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MetaDataBase.h>
-
-namespace android {
-
-static void extractAlbumArt(
- MetaDataBase *fileMeta, const void *data, size_t size) {
- ALOGV("extractAlbumArt from '%s'", (const char *)data);
-
- sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
- if (flacBuffer == NULL) {
- ALOGE("malformed base64 encoded data.");
- return;
- }
-
- size_t flacSize = flacBuffer->size();
- uint8_t *flac = flacBuffer->data();
- ALOGV("got flac of size %zu", flacSize);
-
- uint32_t picType;
- uint32_t typeLen;
- uint32_t descLen;
- uint32_t dataLen;
- char type[128];
-
- if (flacSize < 8) {
- return;
- }
-
- picType = U32_AT(flac);
-
- if (picType != 3) {
- // This is not a front cover.
- return;
- }
-
- typeLen = U32_AT(&flac[4]);
- if (typeLen > sizeof(type) - 1) {
- return;
- }
-
- // we've already checked above that flacSize >= 8
- if (flacSize - 8 < typeLen) {
- return;
- }
-
- memcpy(type, &flac[8], typeLen);
- type[typeLen] = '\0';
-
- ALOGV("picType = %d, type = '%s'", picType, type);
-
- if (!strcmp(type, "-->")) {
- // This is not inline cover art, but an external url instead.
- return;
- }
-
- if (flacSize < 32 || flacSize - 32 < typeLen) {
- return;
- }
-
- descLen = U32_AT(&flac[8 + typeLen]);
- if (flacSize - 32 - typeLen < descLen) {
- return;
- }
-
- dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
- // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
- if (flacSize - 32 - typeLen - descLen < dataLen) {
- return;
- }
-
- ALOGV("got image data, %zu trailing bytes",
- flacSize - 32 - typeLen - descLen - dataLen);
-
- fileMeta->setData(
- kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
-
- fileMeta->setCString(kKeyAlbumArtMIME, type);
-}
-
-void parseVorbisComment(
- MetaDataBase *fileMeta, const char *comment, size_t commentLength)
-{
- struct {
- const char *const mTag;
- uint32_t mKey;
- } kMap[] = {
- { "TITLE", kKeyTitle },
- { "ARTIST", kKeyArtist },
- { "ALBUMARTIST", kKeyAlbumArtist },
- { "ALBUM ARTIST", kKeyAlbumArtist },
- { "COMPILATION", kKeyCompilation },
- { "ALBUM", kKeyAlbum },
- { "COMPOSER", kKeyComposer },
- { "GENRE", kKeyGenre },
- { "AUTHOR", kKeyAuthor },
- { "TRACKNUMBER", kKeyCDTrackNumber },
- { "DISCNUMBER", kKeyDiscNumber },
- { "DATE", kKeyDate },
- { "YEAR", kKeyYear },
- { "LYRICIST", kKeyWriter },
- { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
- { "ANDROID_LOOP", kKeyAutoLoop },
- };
-
- for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
- size_t tagLen = strlen(kMap[j].mTag);
- if (!strncasecmp(kMap[j].mTag, comment, tagLen)
- && comment[tagLen] == '=') {
- if (kMap[j].mKey == kKeyAlbumArt) {
- extractAlbumArt(
- fileMeta,
- &comment[tagLen + 1],
- commentLength - tagLen - 1);
- } else if (kMap[j].mKey == kKeyAutoLoop) {
- if (!strcasecmp(&comment[tagLen + 1], "true")) {
- fileMeta->setInt32(kKeyAutoLoop, true);
- }
- } else {
- fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
- }
- }
- }
-
-}
-
-} // namespace android
diff --git a/media/libmediaextractor/include/media/VorbisComment.h b/media/libmediaextractor/include/media/VorbisComment.h
deleted file mode 100644
index 8ba3295..0000000
--- a/media/libmediaextractor/include/media/VorbisComment.h
+++ /dev/null
@@ -1,30 +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 VORBIS_COMMENT_H_
-#define VORBIS_COMMENT_H_
-
-namespace android {
-
-class MetaDataBase;
-
-void parseVorbisComment(
- MetaDataBase *fileMeta, const char *comment, size_t commentLength);
-
-} // namespace android
-
-#endif // VORBIS_COMMENT_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index c14669f..0a99974 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -101,7 +101,6 @@
kKeyTitle = 'titl', // cstring
kKeyYear = 'year', // cstring
kKeyAlbumArt = 'albA', // compressed image data
- kKeyAlbumArtMIME = 'alAM', // cstring
kKeyAuthor = 'auth', // cstring
kKeyCDTrackNumber = 'cdtr', // cstring
kKeyDiscNumber = 'dnum', // cstring
@@ -198,9 +197,6 @@
// MPEG user data offsets
kKeyMpegUserData = 'mpud', // size_t[]
- // Size of NALU length in mkv/mp4
- kKeyNalLengthSize = 'nals', // int32_t
-
// HDR related
kKeyHdrStaticInfo = 'hdrS', // HDRStaticInfo
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index a26cc81..75d1df0 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -28,6 +28,7 @@
"libcrypto",
"libmediametrics",
"libmediandk",
+ "libmediandk_utils",
"libmediautils",
"libmemunreachable",
"libnativewindow",
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 9dd5e4c..6b27ca7 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -44,8 +44,8 @@
String8 result;
result.append(" MediaPlayer2AudioOutput\n");
- snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
- mStreamType, mLeftVolume, mRightVolume);
+ snprintf(buffer, 255, " stream type(%d), volume(%f)\n",
+ mStreamType, mVolume);
result.append(buffer);
snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
@@ -67,8 +67,7 @@
mCallbackCookie(NULL),
mCallbackData(NULL),
mStreamType(AUDIO_STREAM_MUSIC),
- mLeftVolume(1.0),
- mRightVolume(1.0),
+ mVolume(1.0),
mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
mSampleRateHz(0),
mMsecsPerFrame(0),
@@ -402,7 +401,7 @@
mCallbackData = newcbd;
ALOGV("setVolume");
- t->setVolume(mLeftVolume, mRightVolume);
+ t->setVolume(mVolume);
mSampleRateHz = sampleRate;
mFlags = flags;
@@ -444,7 +443,7 @@
mCallbackData->endTrackSwitch();
}
if (mTrack != 0) {
- mTrack->setVolume(mLeftVolume, mRightVolume);
+ mTrack->setVolume(mVolume);
mTrack->setAuxEffectSendLevel(mSendLevel);
status_t status = mTrack->start();
return status;
@@ -498,13 +497,12 @@
// destruction of the track occurs outside of mutex.
}
-void MediaPlayer2AudioOutput::setVolume(float left, float right) {
- ALOGV("setVolume(%f, %f)", left, right);
+void MediaPlayer2AudioOutput::setVolume(float volume) {
+ ALOGV("setVolume(%f)", volume);
Mutex::Autolock lock(mLock);
- mLeftVolume = left;
- mRightVolume = right;
+ mVolume = volume;
if (mTrack != 0) {
- mTrack->setVolume(left, right);
+ mTrack->setVolume(volume);
}
}
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index ee67abf..fe1005b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -77,7 +77,7 @@
}
void setAudioAttributes(const audio_attributes_t * attributes);
- void setVolume(float left, float right);
+ void setVolume(float volume);
virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
@@ -113,8 +113,7 @@
CallbackData * mCallbackData;
audio_stream_type_t mStreamType;
audio_attributes_t * mAttributes;
- float mLeftVolume;
- float mRightVolume;
+ float mVolume;
AudioPlaybackRate mPlaybackRate;
uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 18254a1..4f73ad3 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -88,7 +88,7 @@
status_t getAudioStreamType(audio_stream_type_t *type);
status_t setLooping(int loop);
bool isLooping();
- status_t setVolume(float leftVolume, float rightVolume);
+ status_t setVolume(float volume);
void notify(int64_t srcId, int msg, int ext1, int ext2,
const PlayerMessage *obj = NULL);
status_t invoke(const PlayerMessage &request, PlayerMessage *reply);
@@ -142,8 +142,7 @@
audio_stream_type_t mStreamType;
Parcel* mAudioAttributesParcel;
bool mLoop;
- float mLeftVolume;
- float mRightVolume;
+ float mVolume;
int mVideoWidth;
int mVideoHeight;
audio_session_t mAudioSessionId;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index d9c9826..480a630 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -321,7 +321,7 @@
mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
mCurrentState = MEDIA_PLAYER2_IDLE;
mLoop = false;
- mLeftVolume = mRightVolume = 1.0;
+ mVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -403,6 +403,15 @@
if (dsd == NULL) {
return BAD_VALUE;
}
+ // Microsecond is used in NuPlayer2.
+ if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
+ dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
+ ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+ }
+ if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
+ dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
+ ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+ }
ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
sp<MediaPlayer2Interface> oldPlayer;
@@ -630,7 +639,7 @@
mPlayer->setLooping(mLoop);
if (mAudioOutput != 0) {
- mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+ mAudioOutput->setVolume(mVolume);
}
if (mAudioOutput != 0) {
@@ -968,13 +977,12 @@
return false;
}
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
- ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+ ALOGV("MediaPlayer2::setVolume(%f)", volume);
Mutex::Autolock _l(mLock);
- mLeftVolume = leftVolume;
- mRightVolume = rightVolume;
+ mVolume = volume;
if (mAudioOutput != 0) {
- mAudioOutput->setVolume(leftVolume, rightVolume);
+ mAudioOutput->setVolume(volume);
}
return OK;
}
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index 26da491..c3c94b6 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -28,6 +28,7 @@
"frameworks/av/media/libstagefright/mpeg2ts",
"frameworks/av/media/libstagefright/rtsp",
"frameworks/av/media/libstagefright/timedtext",
+ "frameworks/av/media/ndk",
],
cflags: [
@@ -49,6 +50,7 @@
"libgui",
"libmedia",
"libmediandk",
+ "libmediandk_utils",
"libpowermanager",
],
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4ce1a88..f795478 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -21,29 +21,20 @@
#include "NuPlayer2Drm.h"
#include "AnotherPacketSource.h"
-#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
-#include <media/MediaHTTPService.h>
-#include <media/MediaSource.h>
#include <media/NdkWrapper.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ClearDataSourceFactory.h>
-#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NdkUtils.h>
#include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
+#include "NdkMediaDataSourceCallbacksPriv.h"
namespace android {
@@ -88,8 +79,6 @@
void NuPlayer2::GenericSource2::resetDataSource() {
ALOGV("resetDataSource");
- mHTTPService.clear();
- mHttpSource.clear();
mDisconnected = false;
mUri.clear();
mUriHeaders.clear();
@@ -109,7 +98,6 @@
}
status_t NuPlayer2::GenericSource2::setDataSource(
- const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers) {
Mutex::Autolock _l(mLock);
@@ -117,7 +105,6 @@
resetDataSource();
- mHTTPService = httpService;
mUri = url;
if (headers) {
@@ -150,7 +137,8 @@
ALOGV("setDataSource (source: %p)", source.get());
resetDataSource();
- mDataSource = source;
+ AMediaDataSource *aSource = convertDataSourceToAMediaDataSource(source);
+ mDataSourceWrapper = new AMediaDataSourceWrapper(aSource);
return OK;
}
@@ -161,24 +149,21 @@
status_t NuPlayer2::GenericSource2::initFromDataSource() {
mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- CHECK(mDataSource != NULL || mFd != -1);
- sp<DataSource> dataSource = mDataSource;
+ CHECK(mFd >=0 || mDataSourceWrapper != NULL);
+ sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
const int fd = mFd;
- const int64_t offset = mOffset;
- const int64_t length = mLength;
mLock.unlock();
// This might take long time if data source is not reliable.
status_t err;
- if (dataSource != nullptr) {
- mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource);
- err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+ if (aSourceWrapper != NULL) {
+ err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
} else {
- err = mExtractor->setDataSource(fd, offset, length);
+ err = mExtractor->setDataSource(fd, mOffset, mLength);
}
if (err != OK) {
- ALOGE("initFromDataSource, failed to create data source!");
+ ALOGE("initFromDataSource, failed to set extractor data source!");
mLock.lock();
return UNKNOWN_ERROR;
}
@@ -190,10 +175,8 @@
return UNKNOWN_ERROR;
}
- mLock.lock();
- mFd = -1;
- mDataSource = dataSource;
mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
+ mLock.lock();
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -214,10 +197,10 @@
}
sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- if (mDataSourceWrapper != nullptr) {
- err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+ if (aSourceWrapper != NULL) {
+ trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
} else {
- err = trackExtractor->setDataSource(fd, offset, length);
+ trackExtractor->setDataSource(fd, mOffset, mLength);
}
const char *mime;
@@ -329,13 +312,13 @@
mLooper->unregisterHandler(id());
mLooper->stop();
}
- if (mDataSource != NULL) {
- mDataSource->close();
+ if (mDataSourceWrapper != NULL) {
+ mDataSourceWrapper->close();
}
resetDataSource();
}
-void NuPlayer2::GenericSource2::prepareAsync() {
+void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
Mutex::Autolock _l(mLock);
ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
@@ -350,59 +333,45 @@
}
sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
+ msg->setInt64("startTimeUs", startTimeUs);
+
msg->post();
}
-void NuPlayer2::GenericSource2::onPrepareAsync() {
- ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
+void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
+ ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
+ mFd, mUri.c_str(), mDataSourceWrapper.get());
- // delayed data source creation
- if (mDataSource == NULL) {
- // set to false first, if the extractor
- // comes back as secure, set it to true then.
- mIsSecure = false;
-
- if (!mUri.empty()) {
- const char* uri = mUri.c_str();
- String8 contentType;
-
- if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
- if (mHttpSource == NULL) {
- ALOGE("Failed to create http source!");
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
- }
-
- mLock.unlock();
- // This might take long time if connection has some issue.
- sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
- mHTTPService, uri, &mUriHeaders, &contentType,
- static_cast<HTTPBase *>(mHttpSource.get()));
- mLock.lock();
- if (!mDisconnected) {
- mDataSource = dataSource;
- }
+ if (!mUri.empty()) {
+ const char* uri = mUri.c_str();
+ size_t numheaders = mUriHeaders.size();
+ const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
+ for (size_t i = 0; i < numheaders; ++i) {
+ key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
+ key_values[i * 2 + 1] = mUriHeaders.valueAt(i).c_str();
}
-
- if (mFd == -1 && mDataSource == NULL) {
- ALOGE("Failed to create data source!");
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
+ mLock.unlock();
+ AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
+ mLock.lock();
+ mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
+ delete[] key_values;
+ // For cached streaming cases, we need to wait for enough
+ // buffering before reporting prepared.
+ mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
}
- if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
- mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+ if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
+ ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
+ notifyPreparedAndCleanup(UNKNOWN_ERROR);
+ return;
}
- // For cached streaming cases, we need to wait for enough
- // buffering before reporting prepared.
- mIsStreaming = (mCachedSource != NULL);
-
// init extractor from data source
status_t err = initFromDataSource();
+ if (mFd >= 0) {
+ close(mFd);
+ mFd = -1;
+ }
if (err != OK) {
ALOGE("Failed to init from data source!");
@@ -429,6 +398,7 @@
FLAG_CAN_SEEK_FORWARD |
FLAG_CAN_SEEK);
+ doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
finishPrepareAsync();
ALOGV("onPrepareAsync: Done");
@@ -438,8 +408,8 @@
ALOGV("finishPrepareAsync");
if (mIsStreaming) {
- mCachedSource->resumeFetchingIfNecessary();
mPreparing = true;
+ ++mPollBufferingGeneration;
schedulePollBuffering();
} else {
notifyPrepared();
@@ -456,9 +426,7 @@
void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- mDataSource.clear();
- mCachedSource.clear();
- mHttpSource.clear();
+ mDataSourceWrapper.clear();
mBitrate = -1;
mPrevBufferPercentage = -1;
@@ -498,53 +466,27 @@
}
void NuPlayer2::GenericSource2::disconnect() {
- sp<DataSource> dataSource, httpSource;
{
Mutex::Autolock _l(mLock);
- dataSource = mDataSource;
- httpSource = mHttpSource;
mDisconnected = true;
}
-
- if (dataSource != NULL) {
- // disconnect data source
- if (dataSource->flags() & DataSource::kIsCachingDataSource) {
- static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
- }
- } else if (httpSource != NULL) {
- static_cast<HTTPBase *>(httpSource.get())->disconnect();
+ if (mDataSourceWrapper != NULL) {
+ mDataSourceWrapper->close();
}
-
- mDataSourceWrapper = NULL;
-
}
status_t NuPlayer2::GenericSource2::feedMoreTSData() {
return OK;
}
-void NuPlayer2::GenericSource2::sendCacheStats() {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
-
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- }
-
- if (err == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatCacheStats);
- notify->setInt32("bandwidth", kbps);
- notify->post();
- }
-}
-
void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
Mutex::Autolock _l(mLock);
switch (msg->what()) {
case kWhatPrepareAsync:
{
- onPrepareAsync();
+ int64_t startTimeUs;
+ CHECK(msg->findInt64("startTimeUs", &startTimeUs));
+ onPrepareAsync(startTimeUs);
break;
}
case kWhatFetchSubtitleData:
@@ -834,8 +776,6 @@
}
if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
&& !mSentPauseOnBuffering && !mPreparing) {
- mCachedSource->resumeFetchingIfNecessary();
- sendCacheStats();
mSentPauseOnBuffering = true;
sp<AMessage> notify = dupNotify();
notify->setInt32("what", kWhatPauseOnBufferingStart);
@@ -1391,7 +1331,6 @@
notifyPrepared();
mPreparing = false;
} else {
- sendCacheStats();
mSentPauseOnBuffering = false;
sp<AMessage> notify = dupNotify();
notify->setInt32("what", kWhatResumeOnBufferingEnd);
@@ -1443,47 +1382,31 @@
}
void NuPlayer2::GenericSource2::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- // Enquires buffering status every second.
- msg->post(1000000ll);
+ if (mIsStreaming) {
+ sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+ msg->setInt32("generation", mPollBufferingGeneration);
+ // Enquires buffering status every second.
+ msg->post(1000000ll);
+ }
}
void NuPlayer2::GenericSource2::onPollBuffering() {
- status_t finalStatus = UNKNOWN_ERROR;
int64_t cachedDurationUs = -1ll;
- ssize_t cachedDataRemaining = -1;
- if (mCachedSource != NULL) {
- cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus == OK) {
- off64_t size;
- int64_t bitrate = 0ll;
- if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
- // |bitrate| uses bits/second unit, while size is number of bytes.
- bitrate = size * 8000000ll / mDurationUs;
- } else if (mBitrate > 0) {
- bitrate = mBitrate;
- }
- if (bitrate > 0) {
- cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
- }
- }
+ sp<AMediaExtractorWrapper> extractor;
+ if (mVideoTrack.mExtractor != NULL) {
+ extractor = mVideoTrack.mExtractor;
+ } else if (mAudioTrack.mExtractor != NULL) {
+ extractor = mAudioTrack.mExtractor;
}
- if (finalStatus != OK) {
- ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyBufferingUpdate(100);
- }
-
- return;
+ if (extractor != NULL) {
+ cachedDurationUs = extractor->getCachedDuration();
}
if (cachedDurationUs >= 0ll) {
- if (mDurationUs > 0ll) {
+ ssize_t sampleSize = extractor->getSampleSize();
+ if (sampleSize >= 0ll) {
int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
if (percentage > 100) {
@@ -1491,9 +1414,11 @@
}
notifyBufferingUpdate(percentage);
+ ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
+ } else {
+ notifyBufferingUpdate(100);
+ ALOGV("onPollBuffering: EOS");
}
-
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
}
schedulePollBuffering();
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 9bc5182..ade1aa3 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -37,11 +37,9 @@
class DataSource;
class IDataSource;
class IMediaSource;
-struct MediaHTTPService;
struct MediaSource;
class MediaBuffer;
struct MediaClock;
-struct NuCachedSource2;
struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
public MediaBufferObserver // Modular DRM
@@ -50,7 +48,6 @@
const sp<MediaClock> &mediaClock);
status_t setDataSource(
- const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers);
@@ -62,7 +59,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual void stop();
@@ -151,7 +148,6 @@
bool mIsStreaming;
uid_t mUID;
const sp<MediaClock> mMediaClock;
- sp<MediaHTTPService> mHTTPService;
AString mUri;
KeyedVector<String8, String8> mUriHeaders;
int mFd;
@@ -159,9 +155,6 @@
int64_t mLength;
bool mDisconnected;
- sp<DataSource> mDataSource;
- sp<NuCachedSource2> mCachedSource;
- sp<DataSource> mHttpSource;
sp<MetaData> mFileMeta;
sp<AMediaDataSourceWrapper> mDataSourceWrapper;
sp<AMediaExtractorWrapper> mExtractor;
@@ -194,7 +187,7 @@
void onSeek(const sp<AMessage>& msg);
status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
- void onPrepareAsync();
+ void onPrepareAsync(int64_t startTimeUs);
void fetchTextData(
uint32_t what, media_track_type type,
@@ -232,8 +225,6 @@
void onPollBuffering();
void notifyBufferingUpdate(int32_t percentage);
- void sendCacheStats();
-
sp<AMessage> getFormat_l(bool audio);
sp<MetaData> getFormatMeta_l(bool audio);
int32_t getDataGeneration(media_track_type type) const;
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
index a61cacd..175be53 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
@@ -99,7 +99,8 @@
return OK;
}
-void NuPlayer2::HTTPLiveSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
if (mLiveLooper == NULL) {
mLiveLooper = new ALooper;
mLiveLooper->setName("http live");
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
index 97d3653..8fc71e2 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
@@ -38,7 +38,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5bd1674..bc17d13 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -212,11 +212,11 @@
: mPID(pid),
mUID(uid),
mMediaClock(mediaClock),
- mSourceFlags(0),
mOffloadAudio(false),
mAudioDecoderGeneration(0),
mVideoDecoderGeneration(0),
mRendererGeneration(0),
+ mEOSMonitorGeneration(0),
mLastStartedPlayingTimeNs(0),
mPreviousSeekTimeUs(0),
mAudioEOS(false),
@@ -240,8 +240,7 @@
mPaused(false),
mPausedByClient(true),
mPausedForBuffering(false),
- mIsDrmProtected(false),
- mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+ mIsDrmProtected(false) {
CHECK(mediaClock != NULL);
clearFlushComplete();
}
@@ -309,7 +308,7 @@
sp<GenericSource2> genericSource =
new GenericSource2(notify, mUID, mMediaClock);
- err = genericSource->setDataSource(httpService, url, headers);
+ err = genericSource->setDataSource(url, headers);
if (err == OK) {
*source = genericSource;
@@ -393,11 +392,13 @@
// Now, source != NULL.
*/
- mDataSourceType = dataSourceType;
+ mCurrentSourceInfo.mDataSourceType = dataSourceType;
sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
msg->setObject("source", source);
msg->setInt64("srcId", dsd->mId);
+ msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+ msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
msg->post();
}
@@ -415,11 +416,13 @@
// Now, source != NULL.
*/
- mNextDataSourceType = dataSourceType;
+ mNextSourceInfo.mDataSourceType = dataSourceType;
sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
msg->setObject("source", source);
msg->setInt64("srcId", dsd->mId);
+ msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+ msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
msg->post();
}
@@ -554,7 +557,7 @@
sp<Source> source;
{
Mutex::Autolock autoLock(mSourceLock);
- source = mSource;
+ source = mCurrentSourceInfo.mSource;
}
if (source != NULL) {
@@ -584,6 +587,11 @@
msg->post();
}
+void NuPlayer2::rewind() {
+ sp<AMessage> msg = new AMessage(kWhatRewind, this);
+ msg->post();
+}
+
void NuPlayer2::writeTrackInfo(
PlayerMessage* reply, const sp<AMessage>& format) const {
if (format == NULL) {
@@ -640,15 +648,17 @@
{
ALOGV("kWhatSetDataSource");
- CHECK(mSource == NULL);
+ CHECK(mCurrentSourceInfo.mSource == NULL);
status_t err = OK;
sp<RefBase> obj;
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mSrcId));
- mSource = static_cast<Source *>(obj.get());
+ CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
+ CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
+ CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
+ mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
} else {
err = UNKNOWN_ERROR;
ALOGE("kWhatSetDataSource, source should not be NULL");
@@ -657,7 +667,7 @@
CHECK(mDriver != NULL);
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetDataSourceCompleted(mSrcId, err);
+ driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
}
break;
}
@@ -671,9 +681,11 @@
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mNextSrcId));
- mNextSource = static_cast<Source *>(obj.get());
- mNextSource->prepareAsync();
+ CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
+ CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
+ CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
+ mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
+ mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
} else {
err = UNKNOWN_ERROR;
}
@@ -686,7 +698,7 @@
ALOGV("kWhatPlayNextDataSource");
int64_t srcId;
CHECK(msg->findInt64("srcId", &srcId));
- if (srcId != mNextSrcId) {
+ if (srcId != mNextSourceInfo.mSrcId) {
notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
return;
}
@@ -707,6 +719,22 @@
break;
}
+ case kWhatEOSMonitor:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ int32_t reason;
+ CHECK(msg->findInt32("reason", &reason));
+
+ if (generation != mEOSMonitorGeneration || reason != MediaClock::TIMER_REASON_REACHED) {
+ break; // stale or reset
+ }
+
+ ALOGV("kWhatEOSMonitor");
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ break;
+ }
+
case kWhatGetBufferingSettings:
{
sp<AReplyToken> replyID;
@@ -715,8 +743,8 @@
ALOGV("kWhatGetBufferingSettings");
BufferingSettings buffering;
status_t err = OK;
- if (mSource != NULL) {
- err = mSource->getBufferingSettings(&buffering);
+ if (mCurrentSourceInfo.mSource != NULL) {
+ err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
} else {
err = INVALID_OPERATION;
}
@@ -738,8 +766,8 @@
BufferingSettings buffering;
readFromAMessage(msg, &buffering);
status_t err = OK;
- if (mSource != NULL) {
- err = mSource->setBufferingSettings(buffering);
+ if (mCurrentSourceInfo.mSource != NULL) {
+ err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
} else {
err = INVALID_OPERATION;
}
@@ -753,7 +781,7 @@
{
ALOGV("onMessageReceived kWhatPrepare");
- mSource->prepareAsync();
+ mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
break;
}
@@ -766,8 +794,8 @@
CHECK(msg->findPointer("reply", (void**)&reply));
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
size_t ccTracks = 0;
@@ -780,7 +808,7 @@
// write inband tracks
for (size_t i = 0; i < inbandTracks; ++i) {
- writeTrackInfo(reply, mSource->getTrackInfo(i));
+ writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
}
// write CC track
@@ -796,13 +824,13 @@
case kWhatGetSelectedTrack:
{
status_t err = INVALID_OPERATION;
- if (mSource != NULL) {
+ if (mCurrentSourceInfo.mSource != NULL) {
err = OK;
int32_t type32;
CHECK(msg->findInt32("type", (int32_t*)&type32));
media_track_type type = (media_track_type)type32;
- ssize_t selectedTrack = mSource->getSelectedTrack(type);
+ ssize_t selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
PlayerMessage* reply;
CHECK(msg->findPointer("reply", (void**)&reply));
@@ -833,8 +861,8 @@
status_t err = INVALID_OPERATION;
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
size_t ccTracks = 0;
if (mCCDecoder != NULL) {
@@ -842,11 +870,11 @@
}
if (trackIndex < inbandTracks) {
- err = mSource->selectTrack(trackIndex, select, timeUs);
+ err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
if (!select && err == OK) {
int32_t type;
- sp<AMessage> info = mSource->getTrackInfo(trackIndex);
+ sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
if (info != NULL
&& info->findInt32("type", &type)
&& type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
@@ -879,10 +907,10 @@
}
int64_t durationUs;
- if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+ if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyDuration(mSrcId, durationUs);
+ driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
}
}
@@ -899,13 +927,15 @@
ALOGD("onSetVideoSurface(%p, %s video decoder)",
(nww == NULL ? NULL : nww->getANativeWindow()),
- (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
+ (mCurrentSourceInfo.mSource != NULL && mStarted
+ && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
&& mVideoDecoder != NULL) ? "have" : "no");
- // Need to check mStarted before calling mSource->getFormat because NuPlayer2 might
- // be in preparing state and it could take long time.
- // When mStarted is true, mSource must have been set.
- if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
+ // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
+ // because NuPlayer2 might be in preparing state and it could take long time.
+ // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
+ if (mCurrentSourceInfo.mSource == NULL || !mStarted
+ || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
// NOTE: mVideoDecoder's mNativeWindow is always non-null
|| (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
performSetSurface(nww);
@@ -972,7 +1002,7 @@
onStart(true /* play */);
}
mPausedByClient = false;
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
break;
}
@@ -1130,21 +1160,22 @@
&& (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
// This is the first time we've found anything playable.
- if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
schedulePollDuration();
}
}
status_t err;
- if ((err = mSource->feedMoreTSData()) != OK) {
+ if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
// We're not currently decoding anything (no audio or
// video tracks found) and we just ran out of input data.
if (err == ERROR_END_OF_STREAM) {
- notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
} else {
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
}
}
break;
@@ -1226,10 +1257,10 @@
CHECK(msg->findMessage("format", &format));
sp<AMessage> inputFormat =
- mSource->getFormat(false /* audio */);
+ mCurrentSourceInfo.mSource->getFormat(false /* audio */);
setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(mSrcId, inputFormat, format);
+ updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
} else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
@@ -1296,28 +1327,39 @@
finishFlushIfPossible(); // Should not occur.
break; // Finish anyways.
}
- if (mSource != nullptr) {
+ if (mCurrentSourceInfo.mSource != nullptr) {
if (audio) {
- if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
- || mNativeWindow == NULL || mNativeWindow->getANativeWindow() == NULL
+ if (mVideoDecoderError
+ || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
+ || mNativeWindow == NULL
+ || mNativeWindow->getANativeWindow() == NULL
|| mVideoDecoder == NULL) {
// When both audio and video have error, or this stream has only audio
// which has error, notify client of error.
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only audio track has error. Video track could be still good to play.
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
}
mAudioDecoderError = true;
} else {
- if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
+ if (mAudioDecoderError
+ || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
|| mAudioSink == NULL || mAudioDecoder == NULL) {
// When both audio and video have error, or this stream has only video
// which has error, notify client of error.
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only video track has error. Audio track could be still good to play.
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
}
mVideoDecoderError = true;
}
@@ -1367,12 +1409,13 @@
audio ? "audio" : "video", finalResult);
notifyListener(
- mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+ mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, finalResult);
}
if ((mAudioEOS || mAudioDecoder == NULL)
&& (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
}
} else if (what == Renderer::kWhatFlushComplete) {
int32_t audio;
@@ -1393,10 +1436,11 @@
handleFlushComplete(audio, false /* isDecoder */);
finishFlushIfPossible();
} else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+ MEDIA2_INFO_VIDEO_RENDERING_START, 0);
} else if (what == Renderer::kWhatMediaRenderingStart) {
ALOGV("media rendering started");
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
} else if (what == Renderer::kWhatAudioTearDown) {
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
@@ -1449,7 +1493,7 @@
int64_t timerUs;
CHECK(msg->findInt64("timerUs", &timerUs));
- notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
break;
}
@@ -1468,20 +1512,20 @@
if (!mStarted) {
if (!mSourceStarted) {
mSourceStarted = true;
- mSource->start();
+ mCurrentSourceInfo.mSource->start();
}
if (seekTimeUs > 0) {
performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
}
if (needNotify) {
- notifyDriverSeekComplete(mSrcId);
+ notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
}
break;
}
// seeks can take a while, so we essentially paused
- notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
mDeferredActions.push_back(
new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
@@ -1500,13 +1544,49 @@
break;
}
+ case kWhatRewind:
+ {
+ ALOGV("kWhatRewind");
+
+ int64_t seekTimeUs = mCurrentSourceInfo.mStartTimeUs;
+ int32_t mode = MediaPlayer2SeekMode::SEEK_CLOSEST;
+
+ if (!mStarted) {
+ if (!mSourceStarted) {
+ mSourceStarted = true;
+ mCurrentSourceInfo.mSource->start();
+ }
+ performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
+ break;
+ }
+
+ // seeks can take a while, so we essentially paused
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
+
+ mDeferredActions.push_back(
+ new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
+ FLUSH_CMD_FLUSH /* video */));
+
+ mDeferredActions.push_back(
+ new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
+
+ // After a flush without shutdown, decoder is paused.
+ // Don't resume it until source seek is done, otherwise it could
+ // start pulling stale data too soon.
+ mDeferredActions.push_back(
+ new ResumeDecoderAction(false /* needNotify */));
+
+ processDeferredActions();
+ break;
+ }
+
case kWhatPause:
{
if (!mStarted) {
onStart(false /* play */);
}
onPause();
- notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
mPausedByClient = true;
break;
}
@@ -1559,8 +1639,8 @@
return;
}
mPaused = false;
- if (mSource != NULL) {
- mSource->resume();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->resume();
} else {
ALOGW("resume called when source is gone or not set");
}
@@ -1583,7 +1663,7 @@
if (!mSourceStarted) {
mSourceStarted = true;
- mSource->start();
+ mCurrentSourceInfo.mSource->start();
}
mOffloadAudio = false;
@@ -1594,22 +1674,23 @@
uint32_t flags = 0;
- if (mSource->isRealTime()) {
+ if (mCurrentSourceInfo.mSource->isRealTime()) {
flags |= Renderer::FLAG_REAL_TIME;
}
- bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
- bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+ bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
+ bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
if (!hasAudio && !hasVideo) {
ALOGE("no metadata for either audio or video source");
- mSource->stop();
+ mCurrentSourceInfo.mSource->stop();
mSourceStarted = false;
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+ MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
return;
}
ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
- sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
@@ -1617,7 +1698,7 @@
}
mOffloadAudio =
- canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
+ canOffloadStream(audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
&& (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
// Modular DRM: Disabling audio offload if the source is protected
@@ -1641,9 +1722,9 @@
status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
if (err != OK) {
- mSource->stop();
+ mCurrentSourceInfo.mSource->stop();
mSourceStarted = false;
- notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
return;
}
@@ -1652,6 +1733,7 @@
mRenderer->setVideoFrameRate(rate);
}
+ addEndTimeMonitor();
// Renderer is created in paused state.
if (play) {
mRenderer->resume();
@@ -1665,11 +1747,23 @@
}
startPlaybackTimer("onstart");
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
postScanSources();
}
+void NuPlayer2::addEndTimeMonitor() {
+ ++mEOSMonitorGeneration;
+
+ if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
+ return;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
+ msg->setInt32("generation", mEOSMonitorGeneration);
+ mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
+}
+
void NuPlayer2::startPlaybackTimer(const char *where) {
Mutex::Autolock autoLock(mPlayingTimeLock);
if (mLastStartedPlayingTimeNs == 0) {
@@ -1691,7 +1785,7 @@
ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
if (played > 0) {
- driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
+ driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
}
}
mLastStartedPlayingTimeNs = 0;
@@ -1709,7 +1803,8 @@
void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
Mutex::Autolock autoLock(mPlayingTimeLock);
- ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+ ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)",
+ mLastStartedRebufferingTimeNs, exitingPlayback);
if (mLastStartedRebufferingTimeNs != 0) {
sp<NuPlayer2Driver> driver = mDriver.promote();
@@ -1719,9 +1814,10 @@
ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
+ driver->notifyMoreRebufferingTimeUs(
+ mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(mSrcId, true);
+ driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
}
}
}
@@ -1737,8 +1833,8 @@
return;
}
mPaused = true;
- if (mSource != NULL) {
- mSource->pause();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->pause();
} else {
ALOGW("pause called when source is gone or not set");
}
@@ -1828,7 +1924,7 @@
status_t err = mRenderer->openAudioSink(
format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
+ AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
if (err != OK) {
// Any failure we turn off mOffloadAudio.
mOffloadAudio = false;
@@ -1881,7 +1977,7 @@
}
void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
- if (mSource == NULL || mAudioSink == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
return;
}
@@ -1891,12 +1987,12 @@
return;
}
- sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
- sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+ sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
+ sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
const bool hasVideo = (videoFormat != NULL);
bool canOffload = canOffloadStream(
- audioMeta, hasVideo, mSource->isStreaming(), streamType)
+ audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
&& (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
// Modular DRM: Disabling audio offload if the source is protected
@@ -1927,7 +2023,7 @@
return OK;
}
- sp<AMessage> format = mSource->getFormat(audio);
+ sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
if (format == NULL) {
return UNKNOWN_ERROR;
@@ -1949,11 +2045,11 @@
mCCDecoder = new CCDecoder(ccNotify);
}
- if (mSourceFlags & Source::FLAG_SECURE) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
format->setInt32("secure", true);
}
- if (mSourceFlags & Source::FLAG_PROTECTED) {
+ if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
format->setInt32("protected", true);
}
@@ -1972,16 +2068,16 @@
determineAudioModeChange(format);
}
if (mOffloadAudio) {
- mSource->setOffloadAudio(true /* offload */);
+ mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
- const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
+ const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+ *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
ALOGV("instantiateDecoder audio DecoderPassThrough hasVideo: %d", hasVideo);
} else {
- mSource->setOffloadAudio(false /* offload */);
+ mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
- *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+ *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
ALOGV("instantiateDecoder audio Decoder");
}
mAudioDecoderError = false;
@@ -1991,7 +2087,8 @@
notify->setInt32("generation", mVideoDecoderGeneration);
*decoder = new Decoder(
- notify, mSource, mPID, mUID, mRenderer, mNativeWindow, mCCDecoder);
+ notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
+ mCCDecoder);
mVideoDecoderError = false;
// enable FRC if high-quality AV sync is requested, even if not
@@ -2008,8 +2105,8 @@
// Modular DRM
if (mIsDrmProtected) {
format->setObject("crypto", mCrypto);
- ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d", mCrypto.get(),
- (mSourceFlags & Source::FLAG_SECURE) != 0);
+ ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
+ mCrypto.get(), (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
}
(*decoder)->configure(format);
@@ -2277,11 +2374,11 @@
}
sp<MetaData> NuPlayer2::getFileMeta() {
- return mSource->getFileFormatMeta();
+ return mCurrentSourceInfo.mSource->getFileFormatMeta();
}
float NuPlayer2::getFrameRate() {
- sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+ sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
if (meta == NULL) {
return 0;
}
@@ -2339,16 +2436,16 @@
ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
(long long)seekTimeUs, seekTimeUs / 1E6, mode);
- if (mSource == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL) {
// This happens when reset occurs right before the loop mode
// asynchronously seeks to the start of the stream.
LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
- "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+ "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
mAudioDecoder.get(), mVideoDecoder.get());
return;
}
mPreviousSeekTimeUs = seekTimeUs;
- mSource->seekTo(seekTimeUs, mode);
+ mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
++mTimedTextGeneration;
// everything's flushed, continue playback.
@@ -2395,17 +2492,17 @@
mRenderer.clear();
++mRendererGeneration;
- if (mSource != NULL) {
- mSource->stop();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->stop();
Mutex::Autolock autoLock(mSourceLock);
- mSource.clear();
+ mCurrentSourceInfo.mSource.clear();
}
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyResetComplete(mSrcId);
+ driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
}
}
@@ -2440,25 +2537,31 @@
++mRendererGeneration;
- if (mSource != NULL) {
- mSource->stop();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->stop();
}
long previousSrcId;
{
Mutex::Autolock autoLock(mSourceLock);
- mSource = mNextSource;
- mNextSource = NULL;
- previousSrcId = mSrcId;
- mSrcId = mNextSrcId;
- ++mNextSrcId; // to distinguish the two sources.
+ previousSrcId = mCurrentSourceInfo.mSrcId;
+
+ mCurrentSourceInfo = mNextSourceInfo;
+ mNextSourceInfo = SourceInfo();
+ mNextSourceInfo.mSrcId = ~mCurrentSourceInfo.mSrcId; // to distinguish the two sources.
}
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+
+ int64_t durationUs;
+ if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
+ driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
+ }
+ notifyListener(
+ mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
}
}
@@ -2467,6 +2570,8 @@
mResetting = false;
mSourceStarted = false;
+ addEndTimeMonitor();
+
// Modular DRM
if (mCrypto != NULL) {
// decoders will be flushed before this so their mCrypto would go away on their own
@@ -2482,7 +2587,7 @@
onStart(true /* play */);
mPausedByClient = false;
- notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
}
void NuPlayer2::performScanSources() {
@@ -2508,7 +2613,7 @@
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetSurfaceComplete(mSrcId);
+ driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
}
}
}
@@ -2540,7 +2645,7 @@
void NuPlayer2::finishResume() {
if (mResumePending) {
mResumePending = false;
- notifyDriverSeekComplete(mSrcId);
+ notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
}
}
@@ -2562,36 +2667,50 @@
switch (what) {
case Source::kWhatPrepared:
{
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
- if (mSource == NULL) {
- // This is a stale notification from a source that was
- // asynchronously preparing when the client called reset().
- // We handled the reset, the source is gone.
- break;
- }
-
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err != OK) {
- // shut down potential secure codecs in case client never calls reset
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
- processDeferredActions();
- } else {
- mPrepared = true;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- // notify duration first, so that it's definitely set when
- // the app received the "prepare complete" callback.
- int64_t durationUs;
- if (mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(srcId, durationUs);
+ ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source:%p, Id(%lld)",
+ mCurrentSourceInfo.mSource.get(), (long long)srcId);
+ if (srcId == mCurrentSourceInfo.mSrcId) {
+ if (mCurrentSourceInfo.mSource == NULL) {
+ // This is a stale notification from a source that was
+ // asynchronously preparing when the client called reset().
+ // We handled the reset, the source is gone.
+ break;
}
- driver->notifyPrepareCompleted(srcId, err);
+
+ int32_t err;
+ CHECK(msg->findInt32("err", &err));
+
+ if (err != OK) {
+ // shut down potential secure codecs in case client never calls reset
+ mDeferredActions.push_back(
+ new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
+ FLUSH_CMD_SHUTDOWN /* video */));
+ processDeferredActions();
+ } else {
+ mPrepared = true;
+ }
+
+ sp<NuPlayer2Driver> driver = mDriver.promote();
+ if (driver != NULL) {
+ // notify duration first, so that it's definitely set when
+ // the app received the "prepare complete" callback.
+ int64_t durationUs;
+ if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
+ driver->notifyDuration(srcId, durationUs);
+ }
+ driver->notifyPrepareCompleted(srcId, err);
+ }
+ } else if (srcId == mNextSourceInfo.mSrcId) {
+ if (mNextSourceInfo.mSource == NULL) {
+ break; // stale
+ }
+
+ sp<NuPlayer2Driver> driver = mDriver.promote();
+ if (driver != NULL) {
+ int32_t err;
+ CHECK(msg->findInt32("err", &err));
+ driver->notifyPrepareCompleted(srcId, err);
+ }
}
break;
@@ -2637,19 +2756,26 @@
driver->notifyListener(
srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
}
- driver->notifyFlagsChanged(srcId, flags);
+ if (srcId == mCurrentSourceInfo.mSrcId) {
+ driver->notifyFlagsChanged(srcId, flags);
+ }
}
- if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
- cancelPollDuration();
- } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (flags & Source::FLAG_DYNAMIC_DURATION)
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- schedulePollDuration();
- }
+ if (srcId == mCurrentSourceInfo.mSrcId) {
+ if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+ && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+ cancelPollDuration();
+ } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+ && (flags & Source::FLAG_DYNAMIC_DURATION)
+ && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+ schedulePollDuration();
+ }
- mSourceFlags = flags;
+ mCurrentSourceInfo.mSourceFlags = flags;
+ } else if (srcId == mNextSourceInfo.mSrcId) {
+ // TODO: handle duration polling for next source.
+ mNextSourceInfo.mSourceFlags = flags;
+ }
break;
}
@@ -2800,8 +2926,8 @@
CHECK(msg->findBuffer("buffer", &buffer));
size_t inbandTracks = 0;
- if (mSource != NULL) {
- inbandTracks = mSource->getTrackCount();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
}
sendSubtitleData(buffer, inbandTracks);
@@ -2810,7 +2936,7 @@
case NuPlayer2::CCDecoder::kWhatTrackAdded:
{
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
break;
}
@@ -2835,7 +2961,7 @@
playerMsg.add_values()->set_int64_value(durationUs);
playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
- notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
}
void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2846,7 +2972,7 @@
playerMsg.add_values()->set_int64_value(timeUs);
playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
- notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
}
void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2876,14 +3002,14 @@
}
if (playerMsg.values_size() > 0) {
- notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
} else { // send an empty timed text
- notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
+ notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
}
}
const char *NuPlayer2::getDataSourceType() {
- switch (mDataSourceType) {
+ switch (mCurrentSourceInfo.mDataSourceType) {
case DATA_SOURCE_TYPE_HTTP_LIVE:
return "HTTPLive";
@@ -2957,7 +3083,7 @@
ALOGD("onPrepareDrm ");
status_t status = INVALID_OPERATION;
- if (mSource == NULL) {
+ if (mCurrentSourceInfo.mSource == NULL) {
ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
return status;
}
@@ -2970,12 +3096,12 @@
status = OK;
sp<AMediaCryptoWrapper> crypto = NULL;
- status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+ status = mCurrentSourceInfo.mSource->prepareDrm(uuid, *drmSessionId, &crypto);
if (crypto == NULL) {
- ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+ ALOGE("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm failed. status: %d", status);
return status;
}
- ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+ ALOGV("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm succeeded");
if (mCrypto != NULL) {
ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p", mCrypto.get());
@@ -3004,8 +3130,8 @@
status_t status;
if (mCrypto != NULL) {
// notifying the source first before removing crypto from codec
- if (mSource != NULL) {
- mSource->releaseDrm();
+ if (mCurrentSourceInfo.mSource != NULL) {
+ mCurrentSourceInfo.mSource->releaseDrm();
}
status=OK;
@@ -3090,4 +3216,22 @@
TRESPASS();
}
+NuPlayer2::SourceInfo::SourceInfo()
+ : mDataSourceType(DATA_SOURCE_TYPE_NONE),
+ mSrcId(0),
+ mSourceFlags(0),
+ mStartTimeUs(0),
+ mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
+}
+
+NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
+ mSource = other.mSource;
+ mDataSourceType = (DATA_SOURCE_TYPE)other.mDataSourceType;
+ mSrcId = other.mSrcId;
+ mSourceFlags = other.mSourceFlags;
+ mStartTimeUs = other.mStartTimeUs;
+ mEndTimeUs = other.mEndTimeUs;
+ return *this;
+}
+
} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e55cdbe..3ecdb01 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -79,6 +79,7 @@
int64_t seekTimeUs,
MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
bool needNotify = false);
+ void rewind();
status_t setVideoScalingMode(int32_t mode);
status_t getTrackInfo(PlayerMessage* reply) const;
@@ -154,6 +155,29 @@
kWhatSetBufferingSettings = 'sBuS',
kWhatPrepareDrm = 'pDrm',
kWhatReleaseDrm = 'rDrm',
+ kWhatRewind = 'reWd',
+ kWhatEOSMonitor = 'eosM',
+ };
+
+ typedef enum {
+ DATA_SOURCE_TYPE_NONE,
+ DATA_SOURCE_TYPE_HTTP_LIVE,
+ DATA_SOURCE_TYPE_RTSP,
+ DATA_SOURCE_TYPE_GENERIC_URL,
+ DATA_SOURCE_TYPE_GENERIC_FD,
+ DATA_SOURCE_TYPE_MEDIA,
+ } DATA_SOURCE_TYPE;
+
+ struct SourceInfo {
+ SourceInfo();
+ SourceInfo &operator=(const SourceInfo &);
+
+ sp<Source> mSource;
+ std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+ int64_t mSrcId;
+ uint32_t mSourceFlags;
+ int64_t mStartTimeUs;
+ int64_t mEndTimeUs;
};
wp<NuPlayer2Driver> mDriver;
@@ -161,12 +185,8 @@
uid_t mUID;
const sp<MediaClock> mMediaClock;
Mutex mSourceLock; // guard |mSource|.
- sp<Source> mSource;
- int64_t mSrcId;
- uint32_t mSourceFlags;
- sp<Source> mNextSource;
- int64_t mNextSrcId;
- uint32_t mNextSourceFlags;
+ SourceInfo mCurrentSourceInfo;
+ SourceInfo mNextSourceInfo;
sp<ANativeWindowWrapper> mNativeWindow;
sp<MediaPlayer2Interface::AudioSink> mAudioSink;
sp<DecoderBase> mVideoDecoder;
@@ -178,6 +198,7 @@
int32_t mAudioDecoderGeneration;
int32_t mVideoDecoderGeneration;
int32_t mRendererGeneration;
+ int32_t mEOSMonitorGeneration;
Mutex mPlayingTimeLock;
int64_t mLastStartedPlayingTimeNs;
@@ -252,18 +273,6 @@
sp<AMediaCryptoWrapper> mCrypto;
bool mIsDrmProtected;
- typedef enum {
- DATA_SOURCE_TYPE_NONE,
- DATA_SOURCE_TYPE_HTTP_LIVE,
- DATA_SOURCE_TYPE_RTSP,
- DATA_SOURCE_TYPE_GENERIC_URL,
- DATA_SOURCE_TYPE_GENERIC_FD,
- DATA_SOURCE_TYPE_MEDIA,
- } DATA_SOURCE_TYPE;
-
- std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
- std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
-
inline const sp<DecoderBase> &getDecoder(bool audio) {
return audio ? mAudioDecoder : mVideoDecoder;
}
@@ -298,6 +307,8 @@
void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
+ void addEndTimeMonitor();
+
void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index cb4b06d..821dc9f 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -298,7 +298,7 @@
case STATE_RUNNING:
{
if (mAtEOS) {
- mPlayer->seekToAsync(0);
+ mPlayer->rewind();
mAtEOS = false;
mPositionUs = -1;
}
@@ -859,7 +859,7 @@
}
}
if (mLooping || mAutoLoop) {
- mPlayer->seekToAsync(0);
+ mPlayer->rewind();
if (mAudioSink != NULL) {
// The renderer has stopped the sink at the end in order to play out
// the last little bit of audio. In looping mode, we need to restart it.
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index 452b781..652cc89 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1563,6 +1563,7 @@
} else {
notifyComplete = mNotifyCompleteVideo;
mNotifyCompleteVideo = false;
+ mVideoRenderingStarted = false;
}
// If we're currently syncing the queues, i.e. dropping audio while
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 662235f..9298a99 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -69,7 +69,7 @@
BufferingSettings* buffering /* nonnull */) = 0;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
- virtual void prepareAsync() = 0;
+ virtual void prepareAsync(int64_t startTimeUs) = 0;
virtual void start() = 0;
virtual void stop() {}
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 1dfe383..53c66c0 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -96,7 +96,8 @@
return OK;
}
-void NuPlayer2::RTSPSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
if (mIsSDP && mHTTPService == NULL) {
notifyPrepared(BAD_VALUE);
return;
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 712c3e5..e5f1716 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -43,7 +43,7 @@
BufferingSettings* buffering /* nonnull */) override;
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual void prepareAsync();
+ virtual void prepareAsync(int64_t startTimeUs);
virtual void start();
virtual void stop();
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
index 30f6fe3..3ad6d6b 100644
--- a/media/libnblog/Merger.cpp
+++ b/media/libnblog/Merger.cpp
@@ -188,6 +188,7 @@
case EVENT_RESERVED:
case EVENT_UPPER_BOUND:
ALOGW("warning: unexpected event %d", it->type);
+ break;
default:
break;
}
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index dfad332..fd53090 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -269,6 +269,7 @@
case EVENT_RESERVED:
case EVENT_UPPER_BOUND:
body.appendFormat("warning: unexpected event %d", it->type);
+ break;
default:
break;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b058552..3080db5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1748,29 +1748,32 @@
}
int32_t storeMeta;
- if (encoder
- && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
- && storeMeta != kMetadataBufferTypeInvalid) {
- IOMX::PortMode mode;
- if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
- mode = IOMX::kPortModeDynamicNativeHandle;
- } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
- storeMeta == kMetadataBufferTypeGrallocSource) {
- mode = IOMX::kPortModeDynamicANWBuffer;
- } else {
- return BAD_VALUE;
+ if (encoder) {
+ IOMX::PortMode mode = IOMX::kPortModePresetByteBuffer;
+ if (msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
+ && storeMeta != kMetadataBufferTypeInvalid) {
+ if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
+ mode = IOMX::kPortModeDynamicNativeHandle;
+ } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
+ storeMeta == kMetadataBufferTypeGrallocSource) {
+ mode = IOMX::kPortModeDynamicANWBuffer;
+ } else {
+ return BAD_VALUE;
+ }
}
err = setPortMode(kPortIndexInput, mode);
if (err != OK) {
return err;
}
- uint32_t usageBits;
- if (mOMXNode->getParameter(
- (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
- &usageBits, sizeof(usageBits)) == OK) {
- inputFormat->setInt32(
- "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+ if (mode != IOMX::kPortModePresetByteBuffer) {
+ uint32_t usageBits;
+ if (mOMXNode->getParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+ &usageBits, sizeof(usageBits)) == OK) {
+ inputFormat->setInt32(
+ "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+ }
}
}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 90a7eb5..d96d358 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -45,7 +45,7 @@
},
},
- shared_libs: ["libmedia"],
+ shared_libs: ["libmedia", "libmediandk"],
}
cc_library_shared {
@@ -194,6 +194,10 @@
"libFLAC",
],
+ header_libs:[
+ "media_ndk_headers",
+ ],
+
export_shared_lib_headers: [
"libmedia",
"android.hidl.allocator@1.0",
@@ -235,52 +239,29 @@
name: "libstagefright_player2",
srcs: [
- "CallbackDataSource.cpp",
- "CallbackMediaSource.cpp",
- "ClearDataSourceFactory.cpp",
"ClearFileSource.cpp",
"DataURISource.cpp",
"HTTPBase.cpp",
"HevcUtils.cpp",
- "InterfaceUtils.cpp",
"MediaClock.cpp",
- "MediaExtractor.cpp",
- "MediaExtractorFactory.cpp",
"NdkUtils.cpp",
- "NuCachedSource2.cpp",
- "RemoteMediaExtractor.cpp",
- "RemoteMediaSource.cpp",
"Utils.cpp",
"VideoFrameScheduler.cpp",
"http/ClearMediaHTTP.cpp",
],
shared_libs: [
- "libbinder",
- "libcutils",
"libgui",
"liblog",
- "libaudioclient",
- "libmediaextractor",
- "libmediametrics",
- "libmediautils",
"libnetd_client",
- "libui",
"libutils",
- "libmedia_helper",
"libstagefright_foundation",
- "libziparchive",
],
static_libs: [
- "libstagefright_esds",
"libmedia_player2_util",
],
- header_libs:[
- "media_plugin_headers",
- ],
-
export_include_dirs: [
"include",
],
diff --git a/media/libstagefright/ClearDataSourceFactory.cpp b/media/libstagefright/ClearDataSourceFactory.cpp
deleted file mode 100644
index 5d23fda..0000000
--- a/media/libstagefright/ClearDataSourceFactory.cpp
+++ /dev/null
@@ -1,117 +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 "ClearDataSourceFactory"
-
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-#include <media/stagefright/ClearDataSourceFactory.h>
-#include <media/stagefright/DataURISource.h>
-#include <utils/String8.h>
-
-namespace android {
-
-// static
-sp<DataSource> ClearDataSourceFactory::CreateFromURI(
- const sp<MediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- String8 *contentType,
- HTTPBase *httpSource) {
- if (contentType != NULL) {
- *contentType = "";
- }
-
- sp<DataSource> source;
- if (!strncasecmp("file://", uri, 7)) {
- source = new ClearFileSource(uri + 7);
- } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- if (httpService == NULL) {
- ALOGE("Invalid http service!");
- return NULL;
- }
-
- if (httpSource == NULL) {
- sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
- }
- httpSource = new ClearMediaHTTP(conn);
- }
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark = false;
- KeyedVector<String8, String8> nonCacheSpecificHeaders;
- if (headers != NULL) {
- nonCacheSpecificHeaders = *headers;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &nonCacheSpecificHeaders,
- &cacheConfig,
- &disconnectAtHighwatermark);
- }
-
- if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
- ALOGE("Failed to connect http source!");
- return NULL;
- }
-
- if (contentType != NULL) {
- *contentType = httpSource->getMIMEType();
- }
-
- source = NuCachedSource2::Create(
- httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
- } else if (!strncasecmp("data:", uri, 5)) {
- source = DataURISource::Create(uri);
- } else {
- // Assume it's a filename.
- source = new ClearFileSource(uri);
- }
-
- if (source == NULL || source->initCheck() != OK) {
- return NULL;
- }
-
- return source;
-}
-
-sp<DataSource> ClearDataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
- sp<ClearFileSource> source = new ClearFileSource(fd, offset, length);
- return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> ClearDataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
- if (httpService == NULL) {
- return NULL;
- }
-
- sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- return NULL;
- } else {
- return new ClearMediaHTTP(conn);
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e00c3c8..ac9eb0b 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <media/NdkMediaFormatPriv.h>
+#include <media/NdkMediaErrorPriv.h>
namespace android {
@@ -102,23 +103,23 @@
MetaDataBase& meta, size_t index, uint32_t flags) {
sp<AMessage> msg = new AMessage();
AMediaFormat *format = AMediaFormat_fromMsg(&msg);
- status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
+ media_status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
sp<MetaData> newMeta = new MetaData();
convertMessageToMetaData(msg, newMeta);
delete format;
meta = *newMeta;
- return ret;
+ return reverse_translate_error(ret);
}
status_t MediaExtractorCUnwrapperV2::getMetaData(MetaDataBase& meta) {
sp<AMessage> msg = new AMessage();
AMediaFormat *format = AMediaFormat_fromMsg(&msg);
- status_t ret = plugin->getMetaData(plugin->data, format);
+ media_status_t ret = plugin->getMetaData(plugin->data, format);
sp<MetaData> newMeta = new MetaData();
convertMessageToMetaData(msg, newMeta);
delete format;
meta = *newMeta;
- return ret;
+ return reverse_translate_error(ret);
}
const char * MediaExtractorCUnwrapperV2::name() {
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 4bd8a51..9fbb20e 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -21,6 +21,7 @@
#include <media/MediaTrack.h>
#include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaErrorPriv.h>
#include <media/NdkMediaFormatPriv.h>
namespace android {
@@ -112,40 +113,40 @@
}
status_t MediaTrackCUnwrapperV2::start() {
- return wrapper->start(wrapper->data);
+ return reverse_translate_error(wrapper->start(wrapper->data));
}
status_t MediaTrackCUnwrapperV2::stop() {
- return wrapper->stop(wrapper->data);
+ return reverse_translate_error(wrapper->stop(wrapper->data));
}
status_t MediaTrackCUnwrapperV2::getFormat(MetaDataBase& format) {
sp<AMessage> msg = new AMessage();
AMediaFormat *tmpFormat = AMediaFormat_fromMsg(&msg);
- status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
+ media_status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
sp<MetaData> newMeta = new MetaData();
convertMessageToMetaData(msg, newMeta);
delete tmpFormat;
format = *newMeta;
- return ret;
+ return reverse_translate_error(ret);
}
status_t MediaTrackCUnwrapperV2::read(MediaBufferBase **buffer, const ReadOptions *options) {
uint32_t opts = 0;
- if (options->getNonBlocking()) {
+ if (options && options->getNonBlocking()) {
opts |= CMediaTrackReadOptions::NONBLOCKING;
}
int64_t seekPosition = 0;
MediaTrack::ReadOptions::SeekMode seekMode;
- if (options->getSeekTo(&seekPosition, &seekMode)) {
+ if (options && options->getSeekTo(&seekPosition, &seekMode)) {
opts |= SEEK;
opts |= (uint32_t) seekMode;
}
- return wrapper->read(wrapper->data, buffer, opts, seekPosition);
+ return reverse_translate_error(wrapper->read(wrapper->data, buffer, opts, seekPosition));
}
bool MediaTrackCUnwrapperV2::supportNonblockingRead() {
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 2475e7b..2cf79c3 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -19,10 +19,14 @@
#include <utils/Log.h>
#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -91,20 +95,21 @@
}
bool MakeAACCodecSpecificData(
- MetaDataBase &meta,
- unsigned profile, unsigned sampling_freq_index,
- unsigned channel_configuration) {
+ uint8_t *csd, /* out */
+ size_t *esds_size, /* in/out */
+ unsigned profile, /* in */
+ unsigned sampling_freq_index, /* in */
+ unsigned channel_configuration, /* in */
+ int32_t *sampling_rate /* out */
+) {
if(sampling_freq_index > 11u) {
return false;
}
- int32_t sampleRate;
- int32_t channelCount;
static const int32_t kSamplingFreq[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000
};
- sampleRate = kSamplingFreq[sampling_freq_index];
- channelCount = channel_configuration;
+ *sampling_rate = kSamplingFreq[sampling_freq_index];
static const uint8_t kStaticESDS[] = {
0x03, 22,
@@ -127,7 +132,9 @@
};
size_t csdSize = sizeof(kStaticESDS) + 2;
- uint8_t *csd = new uint8_t[csdSize];
+ if (csdSize > *esds_size) {
+ return false;
+ }
memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
csd[sizeof(kStaticESDS)] =
@@ -136,14 +143,186 @@
csd[sizeof(kStaticESDS) + 1] =
((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+ *esds_size = csdSize;
+ return true;
+}
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration) {
+
+ if(sampling_freq_index > 11u) {
+ return false;
+ }
+
+ uint8_t csd[2];
+ csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
+ csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+ static const int32_t kSamplingFreq[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000
+ };
+ int32_t sampleRate = kSamplingFreq[sampling_freq_index];
+
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
+
+ return true;
+}
+
+bool MakeAACCodecSpecificData(
+ MetaDataBase &meta,
+ unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration) {
+
+ uint8_t csd[24];
+ size_t csdSize = sizeof(csd);
+ int32_t sampleRate;
+
+ if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
+ channel_configuration, &sampleRate)) {
+ return false;
+ }
+
meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
meta.setInt32(kKeySampleRate, sampleRate);
- meta.setInt32(kKeyChannelCount, channelCount);
-
+ meta.setInt32(kKeyChannelCount, channel_configuration);
meta.setData(kKeyESDS, 0, csd, csdSize);
- delete [] csd;
return true;
}
+
+static void extractAlbumArt(
+ AMediaFormat *fileMeta, const void *data, size_t size) {
+ ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+ size_t inLen = strnlen((const char *)data, size);
+ size_t flacSize = inLen / 4 * 3;
+ uint8_t *flac = new uint8_t[flacSize];
+ if (!decodeBase64(flac, &flacSize, (const char*)data)) {
+ ALOGE("malformed base64 encoded data.");
+ delete[] flac;
+ return;
+ }
+
+ ALOGV("got flac of size %zu", flacSize);
+
+ uint32_t picType;
+ uint32_t typeLen;
+ uint32_t descLen;
+ uint32_t dataLen;
+ char type[128];
+
+ if (flacSize < 8) {
+ delete[] flac;
+ return;
+ }
+
+ picType = U32_AT(flac);
+
+ if (picType != 3) {
+ // This is not a front cover.
+ delete[] flac;
+ return;
+ }
+
+ typeLen = U32_AT(&flac[4]);
+ if (typeLen > sizeof(type) - 1) {
+ delete[] flac;
+ return;
+ }
+
+ // we've already checked above that flacSize >= 8
+ if (flacSize - 8 < typeLen) {
+ delete[] flac;
+ return;
+ }
+
+ memcpy(type, &flac[8], typeLen);
+ type[typeLen] = '\0';
+
+ ALOGV("picType = %d, type = '%s'", picType, type);
+
+ if (!strcmp(type, "-->")) {
+ // This is not inline cover art, but an external url instead.
+ delete[] flac;
+ return;
+ }
+
+ if (flacSize < 32 || flacSize - 32 < typeLen) {
+ delete[] flac;
+ return;
+ }
+
+ descLen = U32_AT(&flac[8 + typeLen]);
+ if (flacSize - 32 - typeLen < descLen) {
+ delete[] flac;
+ return;
+ }
+
+ dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+ // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+ if (flacSize - 32 - typeLen - descLen < dataLen) {
+ delete[] flac;
+ return;
+ }
+
+ ALOGV("got image data, %zu trailing bytes",
+ flacSize - 32 - typeLen - descLen - dataLen);
+
+ AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
+ &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+ delete[] flac;
+}
+
+void parseVorbisComment(
+ AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
+ struct {
+ const char *const mTag;
+ const char *mKey;
+ } kMap[] = {
+ { "TITLE", AMEDIAFORMAT_KEY_TITLE },
+ { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
+ { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+ { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+ { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
+ { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
+ { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
+ { "GENRE", AMEDIAFORMAT_KEY_GENRE },
+ { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
+ { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
+ { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
+ { "DATE", AMEDIAFORMAT_KEY_DATE },
+ { "YEAR", AMEDIAFORMAT_KEY_YEAR },
+ { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
+ { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
+ { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
+ };
+
+ for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+ size_t tagLen = strlen(kMap[j].mTag);
+ if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+ && comment[tagLen] == '=') {
+ if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
+ extractAlbumArt(
+ fileMeta,
+ &comment[tagLen + 1],
+ commentLength - tagLen - 1);
+ } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
+ if (!strcasecmp(&comment[tagLen + 1], "true")) {
+ AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
+ }
+ } else {
+ AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
+ }
+ }
+ }
+
+}
+
} // namespace android
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index e010b3e..610b961 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -132,6 +132,9 @@
{ "date", METADATA_KEY_DATE },
{ "width", METADATA_KEY_VIDEO_WIDTH },
{ "height", METADATA_KEY_VIDEO_HEIGHT },
+ { "colorstandard", METADATA_KEY_COLOR_STANDARD },
+ { "colortransfer", METADATA_KEY_COLOR_TRANSFER },
+ { "colorrange", METADATA_KEY_COLOR_RANGE },
};
static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 231d540..1a01350 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -36,6 +36,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
#include <media/CharacterEncodingDetector.h>
namespace android {
@@ -403,6 +404,25 @@
return mMetaData.valueAt(index).string();
}
+void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
+ sp<AMessage> format = new AMessage();
+ if (convertMetaDataToMessage(meta, &format) != OK) {
+ return;
+ }
+
+ int32_t standard, transfer, range;
+ if (format->findInt32("color-standard", &standard)
+ && format->findInt32("color-transfer", &transfer)
+ && format->findInt32("color-range", &range)) {
+ ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
+ standard, transfer, range);
+
+ mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
+ mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
+ mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
+ }
+}
+
void StagefrightMetadataRetriever::parseMetaData() {
sp<MetaData> meta = mExtractor->getMetaData();
@@ -542,6 +562,8 @@
if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
videoFrameCount = 0;
}
+
+ parseColorAspects(trackMeta);
} else if (!strncasecmp("image/", mime, 6)) {
int32_t isPrimary;
if (trackMeta->findInt32(
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ebc3b33..0c6c45b 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -569,6 +569,62 @@
}
+std::vector<std::pair<const char *, uint32_t>> tagMappings {
+ {
+ { "album", kKeyAlbum },
+ { "albumartist", kKeyAlbumArtist },
+ { "artist", kKeyArtist },
+ { "author", kKeyAuthor },
+ { "cdtracknum", kKeyCDTrackNumber },
+ { "compilation", kKeyCompilation },
+ { "composer", kKeyComposer },
+ { "date", kKeyDate },
+ { "discnum", kKeyDiscNumber },
+ { "genre", kKeyGenre },
+ { "lyricist", kKeyWriter },
+ { "title", kKeyTitle },
+ { "year", kKeyYear },
+ }
+};
+
+void convertMessageToMetaDataTags(const sp<AMessage> &msg, sp<MetaData> &meta) {
+ for (auto elem : tagMappings) {
+ AString value;
+ if (msg->findString(elem.first, &value)) {
+ meta->setCString(elem.second, value.c_str());
+ }
+ }
+ sp<ABuffer> buf;
+ if (msg->findBuffer("albumart", &buf)) {
+ meta->setData(kKeyAlbumArt, MetaDataBase::Type::TYPE_NONE, buf->data(), buf->size());
+ }
+
+ int32_t loop;
+ if (msg->findInt32("loop", &loop)) {
+ meta->setInt32(kKeyAutoLoop, loop);
+ }
+}
+
+void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format) {
+ for (auto elem : tagMappings) {
+ const char *value;
+ if (meta->findCString(elem.second, &value)) {
+ format->setString(elem.first, value, strlen(value));
+ }
+ }
+ uint32_t type;
+ const void* data;
+ size_t size;
+ if (meta->findData(kKeyAlbumArt, &type, &data, &size)) {
+ sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+ format->setBuffer("albumart", buf);
+ }
+ int32_t loop;
+ if (meta->findInt32(kKeyAutoLoop, &loop)) {
+ format->setInt32("loop", loop);
+ }
+}
+
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format) {
return convertMetaDataToMessage(meta.get(), format);
@@ -592,6 +648,8 @@
sp<AMessage> msg = new AMessage;
msg->setString("mime", mime);
+ convertMetaDataToMessageTags(meta, msg);
+
uint32_t type;
const void *data;
size_t size;
@@ -956,6 +1014,56 @@
msg->setInt32("android._is-hdr", (info & hvcc.kInfoIsHdr) != 0);
}
+ uint32_t isoPrimaries, isoTransfer, isoMatrix, isoRange;
+ if (hvcc.findParam32(kColourPrimaries, &isoPrimaries)
+ && hvcc.findParam32(kTransferCharacteristics, &isoTransfer)
+ && hvcc.findParam32(kMatrixCoeffs, &isoMatrix)
+ && hvcc.findParam32(kVideoFullRangeFlag, &isoRange)) {
+ ALOGV("found iso color aspects : primaris=%d, transfer=%d, matrix=%d, range=%d",
+ isoPrimaries, isoTransfer, isoMatrix, isoRange);
+
+ ColorAspects aspects;
+ ColorUtils::convertIsoColorAspectsToCodecAspects(
+ isoPrimaries, isoTransfer, isoMatrix, isoRange, aspects);
+
+ if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+ int32_t primaries;
+ if (meta->findInt32(kKeyColorPrimaries, &primaries)) {
+ ALOGV("unspecified primaries found, replaced to %d", primaries);
+ aspects.mPrimaries = static_cast<ColorAspects::Primaries>(primaries);
+ }
+ }
+ if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+ int32_t transferFunction;
+ if (meta->findInt32(kKeyTransferFunction, &transferFunction)) {
+ ALOGV("unspecified transfer found, replaced to %d", transferFunction);
+ aspects.mTransfer = static_cast<ColorAspects::Transfer>(transferFunction);
+ }
+ }
+ if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+ int32_t colorMatrix;
+ if (meta->findInt32(kKeyColorMatrix, &colorMatrix)) {
+ ALOGV("unspecified matrix found, replaced to %d", colorMatrix);
+ aspects.mMatrixCoeffs = static_cast<ColorAspects::MatrixCoeffs>(colorMatrix);
+ }
+ }
+ if (aspects.mRange == ColorAspects::RangeUnspecified) {
+ int32_t range;
+ if (meta->findInt32(kKeyColorRange, &range)) {
+ ALOGV("unspecified range found, replaced to %d", range);
+ aspects.mRange = static_cast<ColorAspects::Range>(range);
+ }
+ }
+
+ int32_t standard, transfer, range;
+ if (ColorUtils::convertCodecColorAspectsToPlatformAspects(
+ aspects, &range, &standard, &transfer) == OK) {
+ msg->setInt32("color-standard", standard);
+ msg->setInt32("color-transfer", transfer);
+ msg->setInt32("color-range", range);
+ }
+ }
+
parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
} else if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
@@ -1298,6 +1406,8 @@
ALOGW("did not find mime type");
}
+ convertMessageToMetaDataTags(msg, meta);
+
int64_t durationUs;
if (msg->findInt64("durationUs", &durationUs)) {
meta->setInt64(kKeyDuration, durationUs);
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index 4f46be7..c647f5f 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -4,7 +4,7 @@
vndk: {
enabled: true,
},
-
+ double_loadable: true,
srcs: [
"Conversion.cpp",
"FrameDropper.cpp",
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 6d93807..8c1da76 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -1106,6 +1106,14 @@
consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
mConsumer->setConsumerUsageBits(consumerUsage);
+ // Set impl. defined format as default. Depending on the usage flags
+ // the device-specific implementation will derive the exact format.
+ err = mConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to configure surface default format ret: %d", err);
+ return err;
+ }
+
// Sets the default buffer data space
ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumOutstandingAcquires);
mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
index fd1c90d..7e0ae99 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
@@ -176,7 +176,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word32 L_abs(register Word32 L_var1)
+Word32 L_abs(Word32 L_var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
index f609a73..47e1ee8 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
@@ -190,7 +190,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word32 L_shr_r(register Word32 L_var1, register Word16 var2, Flag *pOverflow)
+Word32 L_shr_r(Word32 L_var1, Word16 var2, Flag *pOverflow)
{
Word32 result;
diff --git a/media/libstagefright/codecs/amrnb/common/src/negate.cpp b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
index be58d2b..aa36422 100644
--- a/media/libstagefright/codecs/amrnb/common/src/negate.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
@@ -161,7 +161,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word16 negate(register Word16 var1)
+Word16 negate(Word16 var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/round.cpp b/media/libstagefright/codecs/amrnb/common/src/round.cpp
index 71d1702..633a8c9 100644
--- a/media/libstagefright/codecs/amrnb/common/src/round.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/round.cpp
@@ -184,7 +184,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word16 pv_round(register Word32 L_var1, Flag *pOverflow)
+Word16 pv_round(Word32 L_var1, Flag *pOverflow)
{
Word16 result;
diff --git a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
index 6656f93..cdcc246 100644
--- a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
@@ -193,7 +193,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word16 shr_r(register Word16 var1, register Word16 var2, Flag *pOverflow)
+Word16 shr_r(Word16 var1, Word16 var2, Flag *pOverflow)
{
/*----------------------------------------------------------------------------
; Define all local variables
diff --git a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
index 4868822..36a7393 100644
--- a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
+++ b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
@@ -234,6 +234,7 @@
dec_6p_6N_2(L_index, 4, 0, pos);
add_pulses(pos, 6, k, code);
}
+ break;
default:
break;
}
diff --git a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
index 0325311..4d1126e 100644
--- a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
+++ b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
@@ -170,6 +170,7 @@
case 0x38000000:
case 0x30000000:
i++;
+ break;
default:
;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
index e579bbd..885ab08 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
@@ -160,6 +160,7 @@
case 0x38000000:
case 0x30000000:
i++;
+ break;
default:
;
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index d534f64..ce8d458 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -357,7 +357,10 @@
int32_t numPageSamples = 0;
if (inHeader) {
- if (mInputBufferCount < 2) {
+ // Assume the very first 2 buffers are always codec config (in this case mState is NULL)
+ // After flush, handle CSD
+ if (mInputBufferCount < 2 &&
+ (mState == NULL || (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG))) {
const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
size_t size = inHeader->nFilledLen;
@@ -380,7 +383,24 @@
makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
- if (mInputBufferCount == 0) {
+ // Assume very first frame is identification header - or reset identification
+ // header after flush, but allow only specifying setup header after flush if
+ // identification header was already set up.
+ if (mInputBufferCount == 0 &&
+ (mVi == NULL || data[0] == 1 /* identification header */)) {
+ // remove any prior state
+ if (mVi != NULL) {
+ // also clear mState as it may refer to the old mVi
+ if (mState != NULL) {
+ vorbis_dsp_clear(mState);
+ delete mState;
+ mState = NULL;
+ }
+ vorbis_info_clear(mVi);
+ delete mVi;
+ mVi = NULL;
+ }
+
CHECK(mVi == NULL);
mVi = new vorbis_info;
vorbis_info_init(mVi);
@@ -392,8 +412,15 @@
return;
}
} else {
+ // remove any prior state
+ if (mState != NULL) {
+ vorbis_dsp_clear(mState);
+ delete mState;
+ mState = NULL;
+ }
+
int ret = _vorbis_unpack_books(mVi, &bits);
- if (ret != 0) {
+ if (ret != 0 || mState != NULL) {
notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
mSignalledError = true;
return;
@@ -409,6 +436,7 @@
notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
mOutputPortSettingsChange = AWAITING_DISABLED;
}
+ mInputBufferCount = 1;
}
if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
@@ -550,19 +578,10 @@
mInputBufferCount = 0;
mNumFramesOutput = 0;
- if (mState != NULL) {
- vorbis_dsp_clear(mState);
- delete mState;
- mState = NULL;
- }
- if (mVi != NULL) {
- vorbis_info_clear(mVi);
- delete mVi;
- mVi = NULL;
- }
mSawInputEos = false;
mSignalledOutputEos = false;
mNumFramesLeftOnPage = -1;
+ vorbis_dsp_restart(mState);
}
}
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 9921636..768cbd6 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -170,7 +170,9 @@
int64_t whenUs;
if (delayUs > 0) {
- whenUs = GetNowUs() + delayUs;
+ int64_t nowUs = GetNowUs();
+ whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
+
} else {
whenUs = GetNowUs();
}
@@ -208,6 +210,9 @@
if (whenUs > nowUs) {
int64_t delayUs = whenUs - nowUs;
+ if (delayUs > INT64_MAX / 1000) {
+ delayUs = INT64_MAX / 1000;
+ }
mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
return true;
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index 8f32582..834b88f 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -28,14 +28,31 @@
return NULL;
}
+ size_t bufSize = n / 4 * 3;
+ sp<ABuffer> buf = new ABuffer(bufSize);
+
+ if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
+ buf->setRange(0, bufSize);
+ return buf;
+ }
+ return NULL;
+}
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
+ size_t n = strlen(s);
+
+ if ((n % 4) != 0) {
+ return false;
+ }
+
size_t padding = 0;
- if (n >= 1 && s.c_str()[n - 1] == '=') {
+ if (n >= 1 && s[n - 1] == '=') {
padding = 1;
- if (n >= 2 && s.c_str()[n - 2] == '=') {
+ if (n >= 2 && s[n - 2] == '=') {
padding = 2;
- if (n >= 3 && s.c_str()[n - 3] == '=') {
+ if (n >= 3 && s[n - 3] == '=') {
padding = 3;
}
}
@@ -45,15 +62,13 @@
// already made sure that n % 4 == 0.
size_t outLen = (n / 4) * 3 - padding;
- sp<ABuffer> buffer = new ABuffer(outLen);
- uint8_t *out = buffer->data();
- if (out == NULL || buffer->size() < outLen) {
- return NULL;
+ if (out == NULL || *inOutBufSize < outLen) {
+ return false;
}
size_t j = 0;
uint32_t accum = 0;
for (size_t i = 0; i < n; ++i) {
- char c = s.c_str()[i];
+ char c = s[i];
unsigned value;
if (c >= 'A' && c <= 'Z') {
value = c - 'A';
@@ -66,10 +81,10 @@
} else if (c == '/' || c == '_') {
value = 63;
} else if (c != '=') {
- return NULL;
+ return false;
} else {
if (i < n - padding) {
- return NULL;
+ return false;
}
value = 0;
@@ -86,7 +101,8 @@
}
}
- return buffer;
+ *inOutBufSize = j;
+ return true;
}
static char encode6Bit(unsigned x) {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index abc95e0..60fb9ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -26,6 +26,9 @@
struct AString;
sp<ABuffer> decodeBase64(const AString &s);
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s);
+
void encodeBase64(const void *data, size_t size, AString *out);
void encodeBase64Url(const void *data, size_t size, AString *out);
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 2f933a0..2907751 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -37,6 +37,7 @@
"libcutils",
"libmedia",
"libmediaextractor",
+ "libmediandk",
"libstagefright",
"libstagefright_foundation",
"libutils",
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 37f9d50..b42c053 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -3,6 +3,10 @@
srcs: ["ID3.cpp"],
+ header_libs: [
+ "media_ndk_headers",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index a7090ad..c50677a 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -65,6 +65,7 @@
sp<ImageDecoder> mImageDecoder;
int mLastImageIndex;
void parseMetaData();
+ void parseColorAspects(const sp<MetaData>& meta);
// Delete album art and clear metadata.
void clearMetadata();
diff --git a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
deleted file mode 100644
index 12bcdd3..0000000
--- a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
+++ /dev/null
@@ -1,45 +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 DATA_SOURCE_FACTORY2_H_
-
-#define DATA_SOURCE_FACTORY2_H_
-
-#include <sys/types.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct MediaHTTPService;
-class String8;
-struct HTTPBase;
-
-class ClearDataSourceFactory {
-public:
- static sp<DataSource> CreateFromURI(
- const sp<MediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- String8 *contentType = NULL,
- HTTPBase *httpSource = NULL);
-
- static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
- static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-};
-
-} // namespace android
-
-#endif // DATA_SOURCE_FACTORY2_H_
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index 4a7107d..e87c7f9 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -20,14 +20,23 @@
#include <media/stagefright/MetaData.h>
+struct AMediaFormat;
+
namespace android {
struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration);
+
+void parseVorbisComment(
+ AMediaFormat *fileMeta, const char *comment, size_t commentLength);
+
} // namespace android
#endif // META_DATA_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index fbf1496..7e00eb8 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -38,6 +38,10 @@
"android.hidl.memory@1.0",
],
+ header_libs: [
+ "media_ndk_headers",
+ ],
+
whole_static_libs: [
"libstagefright_metadatautils",
],
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 99762b9..68b375a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -536,6 +536,9 @@
}
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
if (cmd == OMX_CommandStateSet) {
// There are no configurations past first StateSet command.
@@ -600,6 +603,9 @@
status_t OMXNodeInstance::getParameter(
OMX_INDEXTYPE index, void *params, size_t /* size */) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
if (isProhibitedIndex_l(index)) {
android_errorWriteLog(0x534e4554, "29422020");
@@ -618,6 +624,10 @@
status_t OMXNodeInstance::setParameter(
OMX_INDEXTYPE index, const void *params, size_t size) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
@@ -639,6 +649,9 @@
status_t OMXNodeInstance::getConfig(
OMX_INDEXTYPE index, void *params, size_t /* size */) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
if (isProhibitedIndex_l(index)) {
android_errorWriteLog(0x534e4554, "29422020");
@@ -657,6 +670,10 @@
status_t OMXNodeInstance::setConfig(
OMX_INDEXTYPE index, const void *params, size_t size) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
@@ -673,6 +690,9 @@
status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
if (portIndex >= NELEM(mPortMode)) {
ALOGE("b/31385713, portIndex(%u)", portIndex);
@@ -855,6 +875,9 @@
status_t OMXNodeInstance::getGraphicBufferUsage(
OMX_U32 portIndex, OMX_U32* usage) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
@@ -968,6 +991,10 @@
OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
OMX_U32 maxFrameHeight) {
Mutex::Autolock autolock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
if (mSailed) {
android_errorWriteLog(0x534e4554, "29422020");
return INVALID_OPERATION;
@@ -1008,6 +1035,10 @@
OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
native_handle_t **sidebandHandle) {
Mutex::Autolock autolock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
if (mSailed) {
android_errorWriteLog(0x534e4554, "29422020");
return INVALID_OPERATION;
@@ -1062,6 +1093,10 @@
}
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
if (!mSailed) {
ALOGE("b/35467458");
android_errorWriteLog(0x534e4554, "35467458");
@@ -1478,6 +1513,9 @@
status_t OMXNodeInstance::setInputSurface(
const sp<IOMXBufferSource> &bufferSource) {
Mutex::Autolock autolock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
status_t err;
@@ -1544,6 +1582,9 @@
}
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
if (!mSailed) {
ALOGE("b/35467458");
@@ -1600,6 +1641,10 @@
status_t OMXNodeInstance::freeBuffer(
OMX_U32 portIndex, IOMX::buffer_id buffer) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
+
CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
removeActiveBuffer(portIndex, buffer);
@@ -1627,6 +1672,9 @@
status_t OMXNodeInstance::fillBuffer(
IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
if (header == NULL) {
@@ -1677,6 +1725,9 @@
buffer_id buffer, const OMXBuffer &omxBuffer,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
switch (omxBuffer.mBufferType) {
case OMXBuffer::kBufferTypePreset:
@@ -1991,6 +2042,9 @@
status_t OMXNodeInstance::getExtensionIndex(
const char *parameterName, OMX_INDEXTYPE *index) {
Mutex::Autolock autoLock(mLock);
+ if (mHandle == NULL) {
+ return DEAD_OBJECT;
+ }
OMX_ERRORTYPE err = OMX_GetExtensionIndex(
mHandle, const_cast<char *>(parameterName), index);
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index ef36982..31bc837 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -29,6 +29,7 @@
header_libs: [
"libbase_headers",
+ "media_ndk_headers",
],
cflags: [
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0667df1..49e01c0 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -400,8 +400,10 @@
switch (count) {
case 3:
data[offset++] = 0;
+ [[fallthrough]];
case 2:
data[offset++] = 0;
+ [[fallthrough]];
case 1:
data[offset++] = 0;
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index c6c0245..d183516 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -54,6 +54,10 @@
#define UNUSED_UNLESS_VERBOSE(x)
#endif
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
+#endif
+
// If no access units are received within 5 secs, assume that the rtp
// stream has ended and signal end of stream.
static int64_t kAccessUnitTimeoutUs = 10000000ll;
@@ -306,8 +310,10 @@
switch (count) {
case 3:
data[offset++] = 0;
+ FALLTHROUGH_INTENDED;
case 2:
data[offset++] = 0;
+ FALLTHROUGH_INTENDED;
case 1:
data[offset++] = 0;
}
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index f968788..97e1452 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -34,4 +34,8 @@
"libutils",
"liblog",
],
+
+ header_libs: [
+ "media_ndk_headers",
+ ],
}
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 0832944..2dec9fa 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -92,18 +92,18 @@
status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
ALOGE("limit '%s' with %s'%s' attribute", name,
(found ? "" : "no "), attr);
- return -EINVAL;
+ return BAD_VALUE;
}
status_t limitError(const char* name, const char *msg) {
ALOGE("limit '%s' %s", name, msg);
- return -EINVAL;
+ return BAD_VALUE;
}
status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
attr, value);
- return -EINVAL;
+ return BAD_VALUE;
}
}; // unnamed namespace
@@ -232,12 +232,12 @@
while (attrs[i] != nullptr) {
if (strEq(attrs[i], "href")) {
if (attrs[++i] == nullptr) {
- return -EINVAL;
+ return BAD_VALUE;
}
href = attrs[i];
} else {
ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
@@ -252,32 +252,32 @@
continue;
}
ALOGE("invalid include file name: %s", href);
- return -EINVAL;
+ return BAD_VALUE;
}
std::string filename = href;
if (filename.compare(0, 13, "media_codecs_") != 0 ||
filename.compare(filename.size() - 4, 4, ".xml") != 0) {
ALOGE("invalid include file name: %s", href);
- return -EINVAL;
+ return BAD_VALUE;
}
filename.insert(0, mHrefBase);
+ status_t oldParsingStatus = mParsingStatus;
+
parseXMLFile(filename.c_str());
- return mParsingStatus;
+
+ status_t newParsingStatus = mParsingStatus;
+ mParsingStatus = oldParsingStatus;
+ return newParsingStatus;
}
void MediaCodecsXmlParser::startElementHandler(
const char *name, const char **attrs) {
- if (mParsingStatus != OK) {
- return;
- }
-
bool inType = true;
if (strEq(name, "Include")) {
- mParsingStatus = includeXMLFile(attrs);
- if (mParsingStatus == OK) {
+ if (includeXMLFile(attrs) == OK) {
mSectionStack.push_back(mCurrentSection);
mCurrentSection = SECTION_INCLUDE;
}
@@ -300,7 +300,7 @@
case SECTION_SETTINGS:
{
if (strEq(name, "Setting")) {
- mParsingStatus = addSettingFromAttributes(attrs);
+ (void)addSettingFromAttributes(attrs);
}
break;
}
@@ -308,9 +308,7 @@
case SECTION_DECODERS:
{
if (strEq(name, "MediaCodec")) {
- mParsingStatus =
- addMediaCodecFromAttributes(false /* encoder */, attrs);
-
+ (void)addMediaCodecFromAttributes(false /* encoder */, attrs);
mCurrentSection = SECTION_DECODER;
}
break;
@@ -319,9 +317,7 @@
case SECTION_ENCODERS:
{
if (strEq(name, "MediaCodec")) {
- mParsingStatus =
- addMediaCodecFromAttributes(true /* encoder */, attrs);
-
+ (void)addMediaCodecFromAttributes(true /* encoder */, attrs);
mCurrentSection = SECTION_ENCODER;
}
break;
@@ -331,9 +327,9 @@
case SECTION_ENCODER:
{
if (strEq(name, "Quirk")) {
- mParsingStatus = addQuirk(attrs);
+ (void)addQuirk(attrs);
} else if (strEq(name, "Type")) {
- mParsingStatus = addTypeFromAttributes(attrs,
+ (void)addTypeFromAttributes(attrs,
(mCurrentSection == SECTION_ENCODER));
mCurrentSection =
(mCurrentSection == SECTION_DECODER ?
@@ -353,9 +349,9 @@
(strEq(name, "Limit") || strEq(name, "Feature"))) {
ALOGW("ignoring %s specified outside of a Type", name);
} else if (strEq(name, "Limit")) {
- mParsingStatus = addLimit(attrs);
+ (void)addLimit(attrs);
} else if (strEq(name, "Feature")) {
- mParsingStatus = addFeature(attrs);
+ (void)addFeature(attrs);
}
break;
}
@@ -367,10 +363,6 @@
}
void MediaCodecsXmlParser::endElementHandler(const char *name) {
- if (mParsingStatus != OK) {
- return;
- }
-
switch (mCurrentSection) {
case SECTION_SETTINGS:
{
@@ -452,31 +444,31 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addSettingFromAttributes: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
name = attrs[i];
} else if (strEq(attrs[i], "value")) {
if (attrs[++i] == nullptr) {
ALOGE("addSettingFromAttributes: value is null");
- return -EINVAL;
+ return BAD_VALUE;
}
value = attrs[i];
} else if (strEq(attrs[i], "update")) {
if (attrs[++i] == nullptr) {
ALOGE("addSettingFromAttributes: update is null");
- return -EINVAL;
+ return BAD_VALUE;
}
update = attrs[i];
} else {
ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
if (name == nullptr || value == nullptr) {
ALOGE("addSettingFromAttributes: name or value unspecified");
- return -EINVAL;
+ return BAD_VALUE;
}
// Boolean values are converted to "0" or "1".
@@ -489,7 +481,7 @@
if (attribute == mServiceAttributeMap.end()) { // New attribute name
if (mUpdate) {
ALOGE("addSettingFromAttributes: updating non-existing setting");
- return -EINVAL;
+ return BAD_VALUE;
}
mServiceAttributeMap.insert(Attribute(name, value));
} else { // Existing attribute name
@@ -513,39 +505,40 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addMediaCodecFromAttributes: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
name = attrs[i];
} else if (strEq(attrs[i], "type")) {
if (attrs[++i] == nullptr) {
ALOGE("addMediaCodecFromAttributes: type is null");
- return -EINVAL;
+ return BAD_VALUE;
}
type = attrs[i];
} else if (strEq(attrs[i], "update")) {
if (attrs[++i] == nullptr) {
ALOGE("addMediaCodecFromAttributes: update is null");
- return -EINVAL;
+ return BAD_VALUE;
}
update = attrs[i];
} else {
ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
if (name == nullptr) {
ALOGE("addMediaCodecFromAttributes: name not found");
- return -EINVAL;
+ return BAD_VALUE;
}
mUpdate = (update != nullptr) && parseBoolean(update);
mCurrentCodec = mCodecMap.find(name);
if (mCurrentCodec == mCodecMap.end()) { // New codec name
if (mUpdate) {
- ALOGE("addMediaCodecFromAttributes: updating non-existing codec");
- return -EINVAL;
+ ALOGW("addMediaCodecFromAttributes: cannot update "
+ "non-existing codec \"%s\".", name);
+ return BAD_VALUE;
}
// Create a new codec in mCodecMap
mCurrentCodec = mCodecMap.insert(
@@ -560,18 +553,26 @@
mCurrentCodec->second.order = mCodecCounter++;
} else { // Existing codec name
if (!mUpdate) {
- ALOGE("addMediaCodecFromAttributes: adding existing codec");
- return -EINVAL;
+ ALOGW("addMediaCodecFromAttributes: trying to add "
+ "existing codec \"%s\"", name);
+ return ALREADY_EXISTS;
}
if (type != nullptr) {
mCurrentType = mCurrentCodec->second.typeMap.find(type);
if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGE("addMediaCodecFromAttributes: updating non-existing type");
- return -EINVAL;
+ ALOGE("addMediaCodecFromAttributes: cannot update "
+ "non-existing type \"%s\" for codec \"%s\"",
+ type, name);
+ return BAD_VALUE;
}
} else {
// This should happen only when the codec has at most one type.
mCurrentType = mCurrentCodec->second.typeMap.begin();
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ ALOGE("addMediaCodecFromAttributes: cannot update "
+ "codec \"%s\" without type specified", name);
+ return BAD_VALUE;
+ }
}
}
@@ -579,6 +580,10 @@
}
status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
+ if (mCurrentCodec == mCodecMap.end()) {
+ return BAD_VALUE;
+ }
+
const char *name = nullptr;
size_t i = 0;
@@ -586,19 +591,19 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addQuirk: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
name = attrs[i];
} else {
ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
if (name == nullptr) {
ALOGE("addQuirk: name not found");
- return -EINVAL;
+ return BAD_VALUE;
}
mCurrentCodec->second.quirkSet.emplace(name);
@@ -606,6 +611,10 @@
}
status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
+ if (mCurrentCodec == mCodecMap.end()) {
+ return BAD_VALUE;
+ }
+
const char *name = nullptr;
const char *update = nullptr;
@@ -614,42 +623,51 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addTypeFromAttributes: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
name = attrs[i];
} else if (strEq(attrs[i], "update")) {
if (attrs[++i] == nullptr) {
ALOGE("addTypeFromAttributes: update is null");
- return -EINVAL;
+ return BAD_VALUE;
}
update = attrs[i];
} else {
ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
if (name == nullptr) {
- return -EINVAL;
+ return BAD_VALUE;
}
mCurrentCodec->second.isEncoder = encoder;
mCurrentType = mCurrentCodec->second.typeMap.find(name);
if (!mUpdate) {
if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
- ALOGE("addTypeFromAttributes: re-defining existing type without update");
- return -EINVAL;
+ ALOGW("addTypeFromAttributes: trying to update "
+ "existing type \"%s\"", name);
+ return ALREADY_EXISTS;
}
mCurrentType = mCurrentCodec->second.typeMap.insert(
Type(name, AttributeMap())).first;
} else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
ALOGE("addTypeFromAttributes: updating non-existing type");
+ return BAD_VALUE;
}
return OK;
}
status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
+ if (mCurrentCodec == mCodecMap.end()) {
+ return BAD_VALUE;
+ }
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ return BAD_VALUE;
+ }
+
const char* a_name = nullptr;
const char* a_default = nullptr;
const char* a_in = nullptr;
@@ -665,78 +683,73 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_name = attrs[i];
} else if (strEq(attrs[i], "default")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: default is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_default = attrs[i];
} else if (strEq(attrs[i], "in")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: in is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_in = attrs[i];
} else if (strEq(attrs[i], "max")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: max is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_max = attrs[i];
} else if (strEq(attrs[i], "min")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: min is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_min = attrs[i];
} else if (strEq(attrs[i], "range")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: range is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_range = attrs[i];
} else if (strEq(attrs[i], "ranges")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: ranges is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_ranges = attrs[i];
} else if (strEq(attrs[i], "scale")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: scale is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_scale = attrs[i];
} else if (strEq(attrs[i], "value")) {
if (attrs[++i] == nullptr) {
ALOGE("addLimit: value is null");
- return -EINVAL;
+ return BAD_VALUE;
}
a_value = attrs[i];
} else {
ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
if (a_name == nullptr) {
ALOGE("limit with no 'name' attribute");
- return -EINVAL;
+ return BAD_VALUE;
}
// size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
// measured-frame-rate, measured-blocks-per-second: range
// quality: range + default + [scale]
// complexity: range + default
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGW("ignoring null type");
- return OK;
- }
-
std::string range;
if (strEq(a_name, "aspect-ratio") ||
strEq(a_name, "bitrate") ||
@@ -880,6 +893,13 @@
}
status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
+ if (mCurrentCodec == mCodecMap.end()) {
+ return BAD_VALUE;
+ }
+ if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+ return BAD_VALUE;
+ }
+
size_t i = 0;
const char *name = nullptr;
int32_t optional = -1;
@@ -890,30 +910,30 @@
if (strEq(attrs[i], "name")) {
if (attrs[++i] == nullptr) {
ALOGE("addFeature: name is null");
- return -EINVAL;
+ return BAD_VALUE;
}
name = attrs[i];
} else if (strEq(attrs[i], "optional")) {
if (attrs[++i] == nullptr) {
ALOGE("addFeature: optional is null");
- return -EINVAL;
+ return BAD_VALUE;
}
optional = parseBoolean(attrs[i]) ? 1 : 0;
} else if (strEq(attrs[i], "required")) {
if (attrs[++i] == nullptr) {
ALOGE("addFeature: required is null");
- return -EINVAL;
+ return BAD_VALUE;
}
required = parseBoolean(attrs[i]) ? 1 : 0;
} else if (strEq(attrs[i], "value")) {
if (attrs[++i] == nullptr) {
ALOGE("addFeature: value is null");
- return -EINVAL;
+ return BAD_VALUE;
}
value = attrs[i];
} else {
ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
- return -EINVAL;
+ return BAD_VALUE;
}
++i;
}
@@ -921,23 +941,18 @@
// Every feature must have a name.
if (name == nullptr) {
ALOGE("feature with no 'name' attribute");
- return -EINVAL;
- }
-
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGW("ignoring null type");
- return OK;
+ return BAD_VALUE;
}
if ((optional != -1) || (required != -1)) {
if (optional == required) {
ALOGE("feature '%s' is both/neither optional and required", name);
- return -EINVAL;
+ return BAD_VALUE;
}
if ((optional == 1) || (required == 1)) {
if (value != nullptr) {
ALOGE("feature '%s' cannot have extra 'value'", name);
- return -EINVAL;
+ return BAD_VALUE;
}
mCurrentType->second[std::string("feature-") + name] =
optional == 1 ? "0" : "1";
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index 3dd4248..3b298a9 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -157,7 +157,7 @@
request->endpoint,
request->buffer,
request->buffer_length,
- 0);
+ 1000);
request->actual_length = result;
return result;
}
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 05c8582..b21a1bb 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -31,6 +31,13 @@
license: "NOTICE",
}
+// for use with header_libs
+cc_library_headers {
+ name: "media_ndk_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"]
+}
+
cc_library_shared {
name: "libmediandk",
@@ -39,7 +46,6 @@
"NdkMediaCrypto.cpp",
"NdkMediaDataSource.cpp",
"NdkMediaExtractor.cpp",
- "NdkMediaError.cpp",
"NdkMediaFormat.cpp",
"NdkMediaMuxer.cpp",
"NdkMediaDrm.cpp",
@@ -57,7 +63,6 @@
cflags: [
"-fvisibility=hidden",
"-DEXPORT=__attribute__((visibility(\"default\")))",
-
"-Werror",
"-Wall",
],
@@ -67,6 +72,8 @@
],
shared_libs: [
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hidl.token@1.0-utils",
"libbinder",
"libmedia",
"libmedia_omx",
@@ -75,12 +82,15 @@
"libmediaextractor",
"libstagefright",
"libstagefright_foundation",
+ "libstagefright_bufferqueue_helper",
"liblog",
"libutils",
"libcutils",
"libandroid",
"libandroid_runtime",
"libbinder",
+ "libhwbinder",
+ "libhidlbase",
"libgui",
"libui",
"libmedia2_jni_core",
@@ -99,7 +109,9 @@
llndk_library {
name: "libmediandk",
symbol_file: "libmediandk.map.txt",
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ ],
}
cc_library {
@@ -107,7 +119,6 @@
srcs: [
"NdkMediaDataSourceCallbacks.cpp",
- "NdkMediaError.cpp",
],
include_dirs: [
@@ -143,3 +154,24 @@
},
},
}
+
+cc_test {
+ name: "AImageReaderWindowHandleTest",
+ srcs: ["tests/AImageReaderWindowHandleTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libmediandk",
+ "libnativewindow",
+ "libgui",
+ "libutils",
+ "libui",
+ "libcutils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ ],
+ cflags: [
+ "-D__ANDROID_VNDK__",
+ ],
+ include_dirs: [
+ "frameworks/av/media/ndk/",
+ ],
+}
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index be635ff..47b0780 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -28,6 +28,7 @@
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <grallocusage/GrallocUsageConversion.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
using namespace android;
@@ -43,6 +44,10 @@
const char* AImageReader::kContextKey = "Context";
const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
+static constexpr int kWindowHalTokenSizeMax = 256;
+
+static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
+
bool
AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
// Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
@@ -363,6 +368,15 @@
mBufferItemConsumer->abandon();
mBufferItemConsumer->setFrameAvailableListener(nullptr);
}
+
+ if (mWindowHandle != nullptr) {
+ int size = mWindowHandle->data[0];
+ hidl_vec<uint8_t> halToken;
+ halToken.setToExternal(
+ reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
+ deleteHalToken(halToken);
+ native_handle_delete(mWindowHandle);
+ }
}
media_status_t
@@ -522,6 +536,25 @@
}
}
+media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
+ if (mWindowHandle != nullptr) {
+ *handle = mWindowHandle;
+ return AMEDIA_OK;
+ }
+ sp<HGraphicBufferProducer> hgbp =
+ new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
+ HalToken halToken;
+ if (!createHalToken(hgbp, &halToken)) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ mWindowHandle = convertHalTokenToNativeHandle(halToken);
+ if (!mWindowHandle) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ *handle = mWindowHandle;
+ return AMEDIA_OK;
+}
+
int
AImageReader::getBufferWidth(BufferItem* buffer) {
if (buffer == NULL) return -1;
@@ -585,6 +618,58 @@
}
}
+static native_handle_t *convertHalTokenToNativeHandle(
+ const HalToken &halToken) {
+ // We attempt to store halToken in the ints of the native_handle_t after its
+ // size. The first int stores the size of the token. We store this in an int
+ // to avoid alignment issues where size_t and int do not have the same
+ // alignment.
+ size_t nhDataByteSize = halToken.size();
+ if (nhDataByteSize > kWindowHalTokenSizeMax) {
+ // The size of the token isn't reasonable..
+ return nullptr;
+ }
+ size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
+
+ // We don't check for overflow, whether numInts can fit in an int, since we
+ // expect kWindowHalTokenSizeMax to be a reasonable limit.
+ // create a native_handle_t with 0 numFds and numInts number of ints.
+ native_handle_t *nh =
+ native_handle_create(0, numInts);
+ if (!nh) {
+ return nullptr;
+ }
+ // Store the size of the token in the first int.
+ nh->data[0] = nhDataByteSize;
+ memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
+ return nh;
+}
+
+static sp<HGraphicBufferProducer> convertNativeHandleToHGBP (
+ const native_handle_t *handle) {
+ // Read the size of the halToken vec<uint8_t>
+ hidl_vec<uint8_t> halToken;
+ halToken.setToExternal(
+ reinterpret_cast<uint8_t *>(const_cast<int *>(&(handle->data[1]))),
+ handle->data[0]);
+ sp<HGraphicBufferProducer> hgbp =
+ HGraphicBufferProducer::castFrom(retrieveHalInterface(halToken));
+ return hgbp;
+}
+
+EXPORT
+sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(
+ const native_handle_t *handle) {
+ if (handle == nullptr) {
+ return nullptr;
+ }
+ if (handle->numFds != 0 ||
+ handle->numInts < ceil(sizeof(size_t) / sizeof(int))) {
+ return nullptr;
+ }
+ return convertNativeHandleToHGBP(handle);
+}
+
EXPORT
media_status_t AImageReader_new(
int32_t width, int32_t height, int32_t format, int32_t maxImages,
@@ -594,6 +679,19 @@
width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
}
+extern "C" {
+
+EXPORT
+media_status_t AImageReader_getWindowNativeHandle(
+ AImageReader *reader, /*out*/native_handle_t **handle) {
+ if (reader == nullptr || handle == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return reader->getWindowNativeHandle(handle);
+}
+
+} //extern "C"
+
EXPORT
media_status_t AImageReader_newWithUsage(
int32_t width, int32_t height, int32_t format, uint64_t usage,
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index bed8a21..a9b54a8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -69,6 +69,8 @@
media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
+ media_status_t getWindowNativeHandle(/*out*/native_handle_t **handle);
+
ANativeWindow* getWindow() const { return mWindow.get(); };
int32_t getWidth() const { return mWidth; };
int32_t getHeight() const { return mHeight; };
@@ -160,10 +162,17 @@
sp<Surface> mSurface;
sp<BufferItemConsumer> mBufferItemConsumer;
sp<ANativeWindow> mWindow;
+ native_handle_t* mWindowHandle = nullptr;
List<AImage*> mAcquiredImages;
Mutex mLock;
};
+// Retrieves HGraphicBufferProducer corresponding to the native_handle_t
+// provided. This method also deletes the HalToken corresponding to the
+// native_handle_t. Thus, if it is used twice in succession, the second call
+// returns nullptr;
+sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(const native_handle_t *handle);
+
#endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 43c89bb..3c10024 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -224,6 +224,11 @@
}
sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+ if (source == NULL) {
+ ALOGE("AMediaDataSource_newUri source is null");
+ return NULL;
+ }
+ ALOGI("AMediaDataSource_newUri source %s flags %u", source->toString().c_str(), source->flags());
AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
aSource->mImpl = source;
aSource->mFlags = source->flags();
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
index 796c11b..f40387f 100644
--- a/media/ndk/NdkMediaDataSourceCallbacks.cpp
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -17,9 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "NdkMediaDataSourceCallbacks"
-#include "NdkMediaErrorPriv.h"
#include "NdkMediaDataSourceCallbacksPriv.h"
#include <media/DataSource.h>
+#include <media/NdkMediaErrorPriv.h>
namespace android {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 2552073..55afb33 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -698,7 +698,7 @@
Vector<uint8_t> byteArray;
byteArray.appendArray(value, valueSize);
- return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
+ return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
byteArray));
}
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index a6adee4..f697bd1 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -20,8 +20,8 @@
#include <media/NdkMediaError.h>
#include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaErrorPriv.h>
#include <media/NdkMediaFormatPriv.h>
-#include "NdkMediaErrorPriv.h"
#include "NdkMediaDataSourcePriv.h"
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 249c76e..22fbb42 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -59,6 +59,9 @@
EXPORT
media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) {
+ if (!to || !from) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
to->mFormat->clear();
to->mFormat->extend(from->mFormat);
return AMEDIA_OK;
@@ -265,27 +268,40 @@
EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUM = "album";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMART = "albumart";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMARTIST = "albumartist";
+EXPORT const char* AMEDIAFORMAT_KEY_ARTIST = "artist";
EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id";
+EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER = "cdtracknum";
EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range";
EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard";
EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPILATION = "compilation";
EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPOSER = "composer";
EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_1 = "csd-1";
EXPORT const char* AMEDIAFORMAT_KEY_CSD_2 = "csd-2";
+EXPORT const char* AMEDIAFORMAT_KEY_DATE = "date";
+EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT = "display-height";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_WIDTH = "display-width";
EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_DELAY = "encoder-delay";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_PADDING = "encoder-padding";
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_GENRE = "genre";
EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
@@ -299,6 +315,8 @@
EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
+EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
+EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
@@ -320,9 +338,11 @@
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_TITLE = "title";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
+EXPORT const char* AMEDIAFORMAT_KEY_YEAR = "year";
} // extern "C"
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index ab709ac..e79926d 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -20,8 +20,8 @@
#include <media/NdkMediaMuxer.h>
#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaErrorPriv.h>
#include <media/NdkMediaFormatPriv.h>
-#include "NdkMediaErrorPriv.h"
#include <utils/Log.h>
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index 68de176..e5d863c 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -37,6 +37,9 @@
#define _NDK_IMAGE_READER_H
#include <sys/cdefs.h>
+#ifdef __ANDROID_VNDK__
+#include <cutils/native_handle.h>
+#endif
#include <android/native_window.h>
#include "NdkMediaError.h"
@@ -461,6 +464,23 @@
media_status_t AImageReader_setBufferRemovedListener(
AImageReader* reader, AImageReader_BufferRemovedListener* listener) __INTRODUCED_IN(26);
+#ifdef __ANDROID_VNDK__
+/*
+ * Get the native_handle_t corresponding to the ANativeWindow owned by the
+ * AImageReader provided.
+ *
+ * @param reader The image reader of interest.
+ * @param handle The output native_handle_t. This native handle is owned by
+ * this image reader.
+ *
+ * @return AMEDIA_OK if the method call succeeds.
+ * AMEDIA_ERROR_INVALID_PARAMETER if reader or handle are NULL.
+ * AMEDIA_ERROR_UNKNOWN if some other error is encountered.
+ */
+media_status_t AImageReader_getWindowNativeHandle(
+ AImageReader *reader, /* out */native_handle_t **handle);
+#endif
+
#endif /* __ANDROID_API__ >= 26 */
__END_DECLS
diff --git a/media/ndk/include/media/NdkMediaError.h b/media/ndk/include/media/NdkMediaError.h
index 75f4605..2be1d6e 100644
--- a/media/ndk/include/media/NdkMediaError.h
+++ b/media/ndk/include/media/NdkMediaError.h
@@ -63,6 +63,7 @@
AMEDIA_ERROR_INVALID_OPERATION = AMEDIA_ERROR_BASE - 5,
AMEDIA_ERROR_END_OF_STREAM = AMEDIA_ERROR_BASE - 6,
AMEDIA_ERROR_IO = AMEDIA_ERROR_BASE - 7,
+ AMEDIA_ERROR_WOULD_BLOCK = AMEDIA_ERROR_BASE - 8,
AMEDIA_DRM_ERROR_BASE = -20000,
AMEDIA_DRM_NOT_PROVISIONED = AMEDIA_DRM_ERROR_BASE - 1,
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 3f853d0..3fc28f3 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -86,10 +86,6 @@
void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
-
-/**
- * XXX should these be ints/enums that we look up in a table as needed?
- */
extern const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION __INTRODUCED_IN(28);
@@ -156,7 +152,6 @@
extern const char* AMEDIAFORMAT_KEY_TRACK_ID __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_WIDTH __INTRODUCED_IN(21);
-
#endif /* __ANDROID_API__ >= 21 */
#if __ANDROID_API__ >= 28
@@ -180,6 +175,25 @@
* copy one AMediaFormat to another
*/
media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
+
+extern const char* AMEDIAFORMAT_KEY_ALBUM __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMART __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPILATION __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPOSER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DATE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DISCNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_DELAY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_PADDING __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);
+
#endif /* __ANDROID_API__ >= 29 */
__END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 224329a..d3bdbae 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -4,6 +4,7 @@
AImageReader_acquireLatestImageAsync; # introduced=26
AImageReader_acquireNextImage; # introduced=24
AImageReader_acquireNextImageAsync; # introduced=26
+ AImageReader_getWindowNativeHandle; #vndk
AImageReader_delete; # introduced=24
AImageReader_getFormat; # introduced=24
AImageReader_getHeight; # introduced=24
@@ -165,6 +166,8 @@
AMediaDrm_setOnEventListener;
AMediaDrm_setPropertyByteArray;
AMediaDrm_setPropertyString;
+ AMediaDrm_setOnExpirationUpdateListener; # introduced=29
+ AMediaDrm_setOnKeysChangeListener; # introduced=29
AMediaDrm_sign;
AMediaDrm_verify;
AMediaExtractor_advance;
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
new file mode 100644
index 0000000..3b5e358
--- /dev/null
+++ b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <media/NdkImageReader.h>
+#include <media/NdkImage.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <NdkImageReaderPriv.h>
+#include <vndk/hardware_buffer.h>
+#include <memory>
+
+namespace android {
+
+using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
+typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
+
+static constexpr uint64_t kImageBufferUsage =
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+static constexpr int kImageWidth = 640;
+static constexpr int kImageHeight = 480;
+static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
+static constexpr int kMaxImages = 1;
+
+static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
+static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
+static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
+static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
+static constexpr int kQueueBufferInputScalingMode = 0;
+static constexpr int kQueueBufferInputTransform = 0;
+static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
+
+static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
+
+class AImageReaderWindowHandleTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
+ kImageBufferUsage , kMaxImages, &imageReader_);
+ media_status_t ret = AMEDIA_ERROR_UNKNOWN;
+ ASSERT_NE(imageReader_, nullptr);
+ ret = AImageReader_setImageListener(imageReader_,
+ &imageReaderAvailableCb_);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ ret = AImageReader_setBufferRemovedListener(imageReader_,
+ &imageReaderDetachedCb_);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ }
+ void TearDown() override {
+ if (imageReader_) {
+ AImageReader_delete(imageReader_);
+ }
+ }
+
+ void HandleImageAvailable() {
+ AImage *outImage = nullptr;
+ media_status_t ret = AMEDIA_OK;
+ auto imageDeleter = [](AImage *img) { AImage_delete(img); };
+ std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+ // Test that the image can be acquired.
+ ret = AImageReader_acquireNextImage(imageReader_, &outImage);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ img.reset(outImage);
+ ASSERT_NE(img, nullptr);
+
+ // Test that we can get a handle to the image's hardware buffer and a
+ // native handle to it.
+ AHardwareBuffer *hardwareBuffer = nullptr;
+ ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ ASSERT_NE(hardwareBuffer, nullptr);
+ const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
+ ASSERT_NE(nh, nullptr);
+ std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+ imageAvailable_ = true;
+ imageCondVar_.notify_one();
+ }
+
+ static void onImageAvailable(void *context, AImageReader *reader) {
+ (void)reader;
+ AImageReaderWindowHandleTest *thisContext =
+ reinterpret_cast<AImageReaderWindowHandleTest *>(context);
+ thisContext->HandleImageAvailable();
+ }
+
+ static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
+ }
+
+ AImageReader *imageReader_ = nullptr;
+ AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
+ AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
+ std::mutex imageAvailableMutex_;
+ std::condition_variable imageCondVar_;
+ bool imageAvailable_ = false;
+};
+
+static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
+ const size_t PIXEL_SIZE = 4;
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ off_t offset = (y * stride + x) * PIXEL_SIZE;
+ for (int c = 0; c < 4; c++) {
+ int parityX = (x / (1 << (c+2))) & 1;
+ int parityY = (y / (1 << (c+2))) & 1;
+ buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
+ }
+ }
+ }
+}
+
+TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
+ // Check that we can create a native_handle_t corresponding to the
+ // AImageReader.
+ native_handle_t *nh = nullptr;
+ AImageReader_getWindowNativeHandle(imageReader_, &nh);
+ ASSERT_NE(nh, nullptr);
+
+ // Check that there are only ints in the handle.
+ ASSERT_EQ(nh->numFds, 0);
+ ASSERT_NE(nh->numInts, 0);
+
+ // Check that the HGBP can be retrieved from the handle.
+ sp<HGraphicBufferProducer> hgbp = AImageReader_getHGBPFromHandle(nh);
+ ASSERT_NE(hgbp, nullptr);
+ sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
+
+ // Test that we can dequeue a buffer.
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ kImageWidth, kImageHeight,
+ kImageFormat, kImageBufferUsage,
+ nullptr, nullptr)));
+ EXPECT_LE(0, dequeuedSlot);
+ EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
+
+ sp<GraphicBuffer> dequeuedBuffer;
+ igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
+ uint8_t* img = nullptr;
+ ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
+
+ // Write in some dummy image data.
+ fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
+ dequeuedBuffer->getStride());
+ ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
+ QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
+ kQueueBufferInputIsAutoTimeStamp,
+ kQueueBufferInputDataspace,
+ kQueueBufferInputRect,
+ kQueueBufferInputScalingMode,
+ kQueueBufferInputTransform,
+ kQueueBufferInputFence);
+ QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
+ &queueBufferOutput));
+ // wait until the onImageAvailable callback is called, or timeout completes.
+ std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+ imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
+ [this]{ return this->imageAvailable_;});
+ EXPECT_TRUE(imageAvailable_) << "Timed out waiting for image data to be handled!\n";
+}
+
+} // namespace android
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 54ef719..802f86f 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,7 +35,6 @@
import android.media.MediaPlayer2;
import android.media.MediaPlayer2.EventCallback;
import android.media.MediaPlayer2Impl;
-import android.media.Metadata;
import android.media.PlaybackParams;
import android.media.SessionToken2;
import android.media.SubtitleData;
@@ -125,7 +124,7 @@
private MediaControlView2 mMediaControlView;
private MediaSession mMediaSession;
private MediaController mMediaController;
- private Metadata mMetadata;
+ private boolean mSeekable;
private MediaMetadata2 mMediaMetadata;
private MediaMetadataRetriever mRetriever;
private boolean mNeedUpdateMediaType;
@@ -262,6 +261,7 @@
mSpeed = 1.0f;
mFallbackSpeed = mSpeed;
mSelectedSubtitleTrackIndex = INVALID_TRACK_INDEX;
+ mSeekable = true;
// TODO: add attributes to get this value.
mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
@@ -715,13 +715,14 @@
}
try {
+ final Context context = mInstance.getContext();
+
Log.d(TAG, "openVideo(): creating new MediaPlayer2 instance.");
- mMediaPlayer = new MediaPlayer2Impl();
+ mMediaPlayer = new MediaPlayer2Impl(context);
mSurfaceView.setMediaPlayer(mMediaPlayer);
mTextureView.setMediaPlayer(mMediaPlayer);
mCurrentView.assignSurfaceToMediaPlayer(mMediaPlayer);
- final Context context = mInstance.getContext();
// TODO: Add timely firing logic for more accurate sync between CC and video frame
mSubtitleController = new SubtitleController(context);
mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
@@ -794,33 +795,11 @@
private void updatePlaybackState() {
if (mStateBuilder == null) {
- // Get the capabilities of the player for this stream
- mMetadata = mMediaPlayer.getMetadata(MediaPlayer2.METADATA_ALL,
- MediaPlayer2.BYPASS_METADATA_FILTER);
-
// Add Play action as default
- long playbackActions = PlaybackState.ACTION_PLAY;
- if (mMetadata != null) {
- if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
- || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
- playbackActions |= PlaybackState.ACTION_PAUSE;
- }
- if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
- playbackActions |= PlaybackState.ACTION_REWIND;
- }
- if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
- playbackActions |= PlaybackState.ACTION_FAST_FORWARD;
- }
- if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
- playbackActions |= PlaybackState.ACTION_SEEK_TO;
- }
- } else {
- playbackActions |= (PlaybackState.ACTION_PAUSE |
- PlaybackState.ACTION_REWIND | PlaybackState.ACTION_FAST_FORWARD |
- PlaybackState.ACTION_SEEK_TO);
+ long playbackActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE;
+ if (mSeekable) {
+ playbackActions |= (PlaybackState.ACTION_REWIND |
+ PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_SEEK_TO);
}
mStateBuilder = new PlaybackState.Builder();
mStateBuilder.setActions(playbackActions);
@@ -1003,9 +982,6 @@
private void extractMetadata() {
// Get and set duration and title values as MediaMetadata for MediaControlView2
MediaMetadata.Builder builder = new MediaMetadata.Builder();
- if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
- mTitle = mMetadata.getString(Metadata.TITLE);
- }
builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
builder.putLong(
MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
@@ -1168,6 +1144,8 @@
this.onCompletion(mp, dsd);
} else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) {
this.onBufferingUpdate(mp, dsd, extra);
+ } else if (what == MediaPlayer2.MEDIA_INFO_NOT_SEEKABLE) {
+ mSeekable = false;
}
}
@@ -1179,6 +1157,7 @@
}
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
+ mSeekable = true;
updatePlaybackState();
if (mMediaControlView != null) {
@@ -1253,6 +1232,7 @@
private void onCompletion(MediaPlayer2 mp, DataSourceDesc dsd) {
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
+ mSeekable = true;
updatePlaybackState();
if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
mAudioManager.abandonAudioFocus(null);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 01c5ea2..52a8fa8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6654,6 +6654,7 @@
case TrackBase::PAUSING:
mActiveTracks.remove(activeTrack);
+ activeTrack->mState = TrackBase::PAUSED;
doBroadcast = true;
size--;
continue;
@@ -6675,12 +6676,12 @@
allStopped = false;
break;
- case TrackBase::IDLE:
- i++;
- continue;
-
+ case TrackBase::IDLE: // cannot be on ActiveTracks if idle
+ case TrackBase::PAUSED: // cannot be on ActiveTracks if paused
+ case TrackBase::STOPPED: // cannot be on ActiveTracks if destroyed/terminated
default:
- LOG_ALWAYS_FATAL("Unexpected activeTrackState %d", activeTrackState);
+ LOG_ALWAYS_FATAL("%s: Unexpected active track state:%d, id:%d, tracks:%zu",
+ __func__, activeTrackState, activeTrack->id(), size);
}
activeTracks.add(activeTrack);
@@ -7323,8 +7324,14 @@
{
// This section is a rendezvous between binder thread executing start() and RecordThread
AutoMutex lock(mLock);
+ if (recordTrack->isInvalid()) {
+ recordTrack->clearSyncStartEvent();
+ return INVALID_OPERATION;
+ }
if (mActiveTracks.indexOf(recordTrack) >= 0) {
if (recordTrack->mState == TrackBase::PAUSING) {
+ // We haven't stopped yet (moved to PAUSED and not in mActiveTracks)
+ // so no need to startInput().
ALOGV("active record track PAUSING -> ACTIVE");
recordTrack->mState = TrackBase::ACTIVE;
} else {
@@ -7344,11 +7351,30 @@
bool silenced;
status = AudioSystem::startInput(recordTrack->portId(), &silenced);
mLock.lock();
- // FIXME should verify that recordTrack is still in mActiveTracks
+ if (recordTrack->isInvalid()) {
+ recordTrack->clearSyncStartEvent();
+ if (status == NO_ERROR && recordTrack->mState == TrackBase::STARTING_1) {
+ recordTrack->mState = TrackBase::STARTING_2;
+ // STARTING_2 forces destroy to call stopInput.
+ }
+ return INVALID_OPERATION;
+ }
+ if (recordTrack->mState != TrackBase::STARTING_1) {
+ ALOGW("%s(%d): unsynchronized mState:%d change",
+ __func__, recordTrack->id(), recordTrack->mState);
+ // Someone else has changed state, let them take over,
+ // leave mState in the new state.
+ recordTrack->clearSyncStartEvent();
+ return INVALID_OPERATION;
+ }
+ // we're ok, but perhaps startInput has failed
if (status != NO_ERROR) {
+ ALOGW("%s(%d): startInput failed, status %d",
+ __func__, recordTrack->id(), status);
+ // We are in ActiveTracks if STARTING_1 and valid, so remove from ActiveTracks,
+ // leave in STARTING_1, so destroy() will not call stopInput.
mActiveTracks.remove(recordTrack);
recordTrack->clearSyncStartEvent();
- ALOGV("RecordThread::start error %d", status);
return status;
}
recordTrack->setSilenced(silenced);
@@ -7366,21 +7392,8 @@
recordTrack->mState = TrackBase::STARTING_2;
// signal thread to start
mWaitWorkCV.broadcast();
- if (mActiveTracks.indexOf(recordTrack) < 0) {
- ALOGV("Record failed to start");
- status = BAD_VALUE;
- goto startError;
- }
return status;
}
-
-startError:
- if (recordTrack->isExternalTrack()) {
- AudioSystem::stopInput(recordTrack->portId());
- }
- recordTrack->clearSyncStartEvent();
- // FIXME I wonder why we do not reset the state here?
- return status;
}
void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
@@ -7399,24 +7412,26 @@
bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
ALOGV("RecordThread::stop");
AutoMutex _l(mLock);
+ // if we're invalid, we can't be on the ActiveTracks.
if (mActiveTracks.indexOf(recordTrack) < 0 || recordTrack->mState == TrackBase::PAUSING) {
return false;
}
// note that threadLoop may still be processing the track at this point [without lock]
recordTrack->mState = TrackBase::PAUSING;
- // signal thread to stop
- mWaitWorkCV.broadcast();
- // do not wait for mStartStopCond if exiting
- if (exitPending()) {
- return true;
+
+ while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
+ mWaitWorkCV.broadcast(); // signal thread to stop
+ mStartStopCond.wait(mLock);
}
- // FIXME incorrect usage of wait: no explicit predicate or loop
- mStartStopCond.wait(mLock);
- // if we have been restarted, recordTrack is in mActiveTracks here
- if (exitPending() || mActiveTracks.indexOf(recordTrack) < 0) {
+
+ if (recordTrack->mState == TrackBase::PAUSED) { // successful stop
ALOGV("Record stopped OK");
return true;
}
+
+ // don't handle anything - we've been invalidated or restarted and in a different state
+ ALOGW_IF("%s(%d): unsynchronized stop, state: %d",
+ __func__, recordTrack->id(), recordTrack->mState);
return false;
}
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92e79f2..c94639b 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -25,13 +25,13 @@
public:
enum track_state {
IDLE,
- FLUSHED,
+ FLUSHED, // for PlaybackTracks only
STOPPED,
// next 2 states are currently used for fast tracks
// and offloaded tracks only
STOPPING_1, // waiting for first underrun
STOPPING_2, // waiting for presentation complete
- RESUMING,
+ RESUMING, // for PlaybackTracks only
ACTIVE,
PAUSING,
PAUSED,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a99bbe1..f2617ae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1823,17 +1823,34 @@
// see comments at AudioFlinger::PlaybackThread::Track::destroy()
sp<RecordTrack> keep(this);
{
- if (isExternalTrack()) {
- if (mState == ACTIVE || mState == RESUMING) {
- AudioSystem::stopInput(mPortId);
- }
- AudioSystem::releaseInput(mPortId);
- }
+ track_state priorState = mState;
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
RecordThread *recordThread = (RecordThread *) thread.get();
- recordThread->destroyTrack_l(this);
+ priorState = mState;
+ recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
+ }
+ // APM portid/client management done outside of lock.
+ // NOTE: if thread doesn't exist, the input descriptor probably doesn't either.
+ if (isExternalTrack()) {
+ switch (priorState) {
+ case ACTIVE: // invalidated while still active
+ case STARTING_2: // invalidated/start-aborted after startInput successfully called
+ case PAUSING: // invalidated while in the middle of stop() pausing (still active)
+ AudioSystem::stopInput(mPortId);
+ break;
+
+ case STARTING_1: // invalidated/start-aborted and startInput not successful
+ case PAUSED: // OK, not active
+ case IDLE: // OK, not active
+ break;
+
+ case STOPPED: // unexpected (destroyed)
+ default:
+ LOG_ALWAYS_FATAL("%s(%d): invalid prior state: %d", __func__, mId, priorState);
+ }
+ AudioSystem::releaseInput(mPortId);
}
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index f86e75a..a948ea9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -38,7 +38,7 @@
class AudioRouteVector : public Vector<sp<AudioRoute> >
{
public:
- status_t dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 4ac508f..996347b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -18,6 +18,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include <system/audio.h>
namespace android {
@@ -53,7 +54,7 @@
int getMaxRampInMs() const { return mGain.max_ramp_ms; }
// TODO: remove dump from here (split serialization)
- void dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
void getDefaultConfig(struct audio_gain_config *config);
status_t checkConfig(const struct audio_gain_config *config);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index df3b41e..6e4c044 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -41,7 +41,7 @@
audio_port_handle_t getId() const;
audio_module_handle_t getModuleHandle() const;
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
audio_io_handle_t mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this input is routed to
@@ -127,7 +127,7 @@
sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 257209a..ed995e0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -44,7 +44,7 @@
AudioPolicyClientInterface *clientInterface);
virtual ~AudioOutputDescriptor() {}
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
void log(const char* indent);
audio_port_handle_t getId() const;
@@ -150,8 +150,7 @@
AudioPolicyClientInterface *clientInterface);
virtual ~SwAudioOutputDescriptor() {}
- status_t dump(int fd);
-
+ void dump(String8 *dst) const override;
virtual audio_devices_t device() const;
virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
virtual audio_devices_t supportedDevices();
@@ -207,7 +206,7 @@
AudioPolicyClientInterface *clientInterface);
virtual ~HwAudioOutputDescriptor() {}
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
virtual audio_devices_t supportedDevices();
virtual bool setVolume(float volume,
@@ -276,7 +275,7 @@
sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
class HwAudioOutputCollection :
@@ -290,7 +289,7 @@
*/
bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
index c1c3f3c..0843fea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -22,6 +22,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
+#include <utils/String8.h>
namespace android {
@@ -30,7 +31,7 @@
public:
AudioPatch(const struct audio_patch *patch, uid_t uid);
- status_t dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
audio_patch_handle_t mHandle;
struct audio_patch mPatch;
@@ -47,7 +48,7 @@
status_t listAudioPatches(unsigned int *num_patches, struct audio_patch *patches) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 8fc6fe9..96c00ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -43,7 +43,7 @@
void setMix(AudioMix &mix);
- status_t dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
private:
AudioMix mMix; // Audio policy mix descriptor
@@ -80,7 +80,7 @@
status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index bd7517f..ebb9352 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -132,7 +132,8 @@
void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
const AudioRouteVector &getRoutes() const { return mRoutes; }
- void dump(int fd, int spaces, bool verbose = true) const;
+ void dump(String8 *dst, int spaces, bool verbose = true) const;
+
void log(const char* indent) const;
AudioGainCollection mGains; // gain controllers
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index a1ee708..b588d57 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -112,7 +112,7 @@
bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
String8 mName;
@@ -165,7 +165,7 @@
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 6b24fde..330f1d4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -46,7 +46,7 @@
audio_route_type_t getType() const { return mType; }
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
AudioPortVector mSources;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 8d7914b..030bf4b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -45,8 +45,7 @@
mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
~ClientDescriptor() override = default;
- status_t dump(int fd, int spaces, int index);
- virtual status_t dump(String8& dst, int spaces, int index);
+ virtual void dump(String8 *dst, int spaces, int index) const;
virtual std::string toShortString() const;
audio_port_handle_t portId() const { return mPortId; }
@@ -72,10 +71,6 @@
const audio_config_base_t mConfig;
audio_port_handle_t mPreferredDeviceId; // selected input device port ID
bool mActive;
-
-protected:
- // FIXME: use until other descriptor classes have a dump to String8 method
- int mDumpFd;
};
class TrackClientDescriptor: public ClientDescriptor
@@ -90,7 +85,7 @@
~TrackClientDescriptor() override = default;
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
std::string toShortString() const override;
audio_output_flags_t flags() const { return mFlags; }
@@ -115,7 +110,7 @@
~RecordClientDescriptor() override = default;
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
audio_source_t source() const { return mSource; }
audio_input_flags_t flags() const { return mFlags; }
@@ -146,7 +141,7 @@
void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
private:
const sp<AudioPatch> mPatchDesc;
@@ -159,7 +154,7 @@
public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
{
public:
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
@@ -185,19 +180,21 @@
return it->second;
}
virtual void removeClient(audio_port_handle_t portId) {
- LOG_ALWAYS_FATAL_IF(mClients.erase(portId) == 0,
+ auto it = mClients.find(portId);
+ LOG_ALWAYS_FATAL_IF(it == mClients.end(),
"%s(%d): client does not exist", __func__, portId);
+ LOG_ALWAYS_FATAL_IF(it->second->active(),
+ "%s(%d): removing client still active!", __func__, portId);
+ (void)mClients.erase(it);
}
size_t getClientCount() const {
return mClients.size();
}
- String8 dump() const {
- String8 result;
+ virtual void dump(String8 *dst) const {
size_t index = 0;
for (const auto& client: getClientIterable()) {
- client->dump(result, 2, index++);
+ client->dump(dst, 2, index++);
}
- return result;
}
// helper types
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c08e752..83fb10c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -51,7 +51,7 @@
virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
audio_port_handle_t getId() const;
- status_t dump(int fd, int spaces, int index, bool verbose = true) const;
+ void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
void log() const;
String8 mAddress;
@@ -85,7 +85,7 @@
DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
- status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
+ void dump(String8 *dst, const String8 &tag, int spaces = 0, bool verbose = true) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 04831c6..9fa7486 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -21,6 +21,7 @@
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>
+#include <utils/String8.h>
namespace android {
@@ -28,7 +29,7 @@
class EffectDescriptor : public RefBase
{
public:
- status_t dump(int fd);
+ void dump(String8 *dst) const;
int mIo; // io the effect is attached to
routing_strategy mStrategy; // routing strategy the effect is associated to
@@ -50,7 +51,7 @@
uint32_t getMaxEffectsMemory() const;
bool isNonOffloadableEffectEnabled();
- status_t dump(int fd);
+ void dump(String8 *dst) const;
private:
status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 05cfc31..6560431 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,7 +82,7 @@
}
// TODO remove from here (split serialization)
- void dump(int fd);
+ void dump(String8 *dst) const;
private:
void refreshSupportedDevices();
@@ -109,7 +109,7 @@
const char *device_name,
bool matchAddress = true) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 67ac9bc..eb32959 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -73,7 +73,7 @@
uint32_t flags,
bool exactMatchRequiredForInputFlags = false) const;
- void dump(int fd);
+ void dump(String8 *dst) const;
void log();
bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
index e1f6b08..750da55 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -19,6 +19,7 @@
#include <system/audio.h>
#include <Volume.h>
#include <utils/Errors.h>
+#include <utils/String8.h>
namespace android {
@@ -47,7 +48,7 @@
virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
audio_devices_t device) const = 0;
- virtual status_t dump(int fd) const = 0;
+ virtual void dump(String8 *dst) const = 0;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index 50b1037..6266313 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -44,7 +44,7 @@
return mIndexCur.indexOfKey(device) >= 0;
}
- void dump(int fd) const;
+ void dump(String8 *dst) const;
void setVolumeCurvePoint(device_category deviceCategory, const VolumeCurvePoint *point);
const VolumeCurvePoint *getVolumeCurvePoint(device_category deviceCategory) const
@@ -96,7 +96,7 @@
return valueFor(stream).hasVolumeIndexForDevice(device);
}
- virtual status_t dump(int fd) const;
+ void dump(String8 *dst) const override;
private:
void setVolumeCurvePoint(audio_stream_type_t stream, device_category deviceCategory,
diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
index 3e6b2b4..76ec198 100644
--- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -59,7 +59,7 @@
float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
- void dump(int fd) const;
+ void dump(String8 *result) const;
private:
SortedVector<CurvePoint> mCurvePoints;
@@ -144,7 +144,7 @@
}
}
- void dump(int fd, int spaces, bool curvePoints = false) const;
+ void dump(String8 *dst, int spaces, bool curvePoints = false) const;
private:
KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
@@ -217,7 +217,7 @@
return getCurvesFor(stream).hasVolumeIndexForDevice(device);
}
- virtual status_t dump(int fd) const;
+ void dump(String8 *dst) const override;
ssize_t add(const sp<VolumeCurve> &volumeCurve)
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index ca67b87..c90a582 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -35,22 +35,16 @@
return nullptr;
}
-status_t AudioRouteVector::dump(int fd, int spaces) const
+void AudioRouteVector::dump(String8 *dst, int spaces) const
{
if (isEmpty()) {
- return NO_ERROR;
+ return;
}
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\n%*sAudio Routes (%zu):\n", spaces, "", size());
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*s- Route %zu:\n", spaces, "", i + 1);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, 4);
+ dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
+ itemAt(i)->dump(dst, 4);
}
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
index 193d4a6..2725870 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -98,32 +98,17 @@
return NO_ERROR;
}
-void AudioGain::dump(int fd, int spaces, int index) const
+void AudioGain::dump(String8 *dst, int spaces, int index) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
+ dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
+ dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
+ dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
+ dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
+ dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
+ dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
+ dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
+ dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 8ef7707..1f29874 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -257,6 +257,9 @@
mProfile->curActiveCount--;
}
mProfile->curOpenCount--;
+ LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < mProfile->curActiveCount,
+ "%s(%d): mProfile->curOpenCount %d < mProfile->curActiveCount %d.",
+ __func__, mId, mProfile->curOpenCount, mProfile->curActiveCount);
mIoHandle = AUDIO_IO_HANDLE_NONE;
}
}
@@ -272,8 +275,9 @@
// Handle non-client-specific activity ref count
int32_t oldGlobalActiveCount = mGlobalActiveCount;
if (!active && mGlobalActiveCount < 1) {
- ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
- mGlobalActiveCount = 1;
+ LOG_ALWAYS_FATAL("%s(%d) invalid deactivation with globalActiveCount %d",
+ __func__, client->portId(), mGlobalActiveCount);
+ // mGlobalActiveCount = 1;
}
const int delta = active ? 1 : -1;
mGlobalActiveCount += delta;
@@ -336,20 +340,16 @@
return clients;
}
-status_t AudioInputDescriptor::dump(int fd)
+void AudioInputDescriptor::dump(String8 *dst) const
{
- String8 result;
-
- result.appendFormat(" ID: %d\n", getId());
- result.appendFormat(" Sampling rate: %d\n", mSamplingRate);
- result.appendFormat(" Format: %d\n", mFormat);
- result.appendFormat(" Channels: %08x\n", mChannelMask);
- result.appendFormat(" Devices %08x\n", mDevice);
- result.append(" AudioRecord Clients:\n");
- result.append(ClientMapHandler<RecordClientDescriptor>::dump());
- result.append("\n");
- write(fd, result.string(), result.size());
- return NO_ERROR;
+ dst->appendFormat(" ID: %d\n", getId());
+ dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+ dst->appendFormat(" Format: %d\n", mFormat);
+ dst->appendFormat(" Channels: %08x\n", mChannelMask);
+ dst->appendFormat(" Devices %08x\n", mDevice);
+ dst->append(" AudioRecord Clients:\n");
+ ClientMapHandler<RecordClientDescriptor>::dump(dst);
+ dst->append("\n");
}
bool AudioInputCollection::isSourceActive(audio_source_t source) const
@@ -421,20 +421,13 @@
return 0;
}
-status_t AudioInputCollection::dump(int fd) const
+void AudioInputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nInputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nInputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Input %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Input %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 03685ab..4ce6b08 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -276,36 +276,31 @@
return clients;
}
-status_t AudioOutputDescriptor::dump(int fd)
+void AudioOutputDescriptor::dump(String8 *dst) const
{
- String8 result;
-
- result.appendFormat(" ID: %d\n", mId);
- result.appendFormat(" Sampling rate: %d\n", mSamplingRate);
- result.appendFormat(" Format: %08x\n", mFormat);
- result.appendFormat(" Channels: %08x\n", mChannelMask);
- result.appendFormat(" Devices: %08x\n", device());
- result.appendFormat(" Global active count: %u\n", mGlobalActiveCount);
- result.append(" Stream volume activeCount muteCount\n");
+ dst->appendFormat(" ID: %d\n", mId);
+ dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+ dst->appendFormat(" Format: %08x\n", mFormat);
+ dst->appendFormat(" Channels: %08x\n", mChannelMask);
+ dst->appendFormat(" Devices: %08x\n", device());
+ dst->appendFormat(" Global active count: %u\n", mGlobalActiveCount);
+ dst->append(" Stream volume activeCount muteCount\n");
for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- result.appendFormat(" %02d %.03f %02d %02d\n",
+ dst->appendFormat(" %02d %.03f %02d %02d\n",
i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
}
- result.append(" AudioTrack Clients:\n");
- result.append(ClientMapHandler<TrackClientDescriptor>::dump());
- result.append("\n");
+ dst->append(" AudioTrack Clients:\n");
+ ClientMapHandler<TrackClientDescriptor>::dump(dst);
+ dst->append("\n");
if (mActiveClients.size() > 0) {
- result.append(" AudioTrack active (stream) clients:\n");
+ dst->append(" AudioTrack active (stream) clients:\n");
size_t index = 0;
for (const auto& clientPair : mActiveClients) {
- result.appendFormat(" Refcount: %zu", clientPair.second);
- clientPair.first->dump(result, 2, index++);
+ dst->appendFormat(" Refcount: %zu", clientPair.second);
+ clientPair.first->dump(dst, 2, index++);
}
- result.append(" \n");
+ dst->append(" \n");
}
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
}
void AudioOutputDescriptor::log(const char* indent)
@@ -328,17 +323,11 @@
}
}
-status_t SwAudioOutputDescriptor::dump(int fd)
+void SwAudioOutputDescriptor::dump(String8 *dst) const
{
- String8 result;
-
- result.appendFormat(" Latency: %d\n", mLatency);
- result.appendFormat(" Flags %08x\n", mFlags);
- write(fd, result.string(), result.size());
-
- AudioOutputDescriptor::dump(fd);
-
- return NO_ERROR;
+ dst->appendFormat(" Latency: %d\n", mLatency);
+ dst->appendFormat(" Flags %08x\n", mFlags);
+ AudioOutputDescriptor::dump(dst);
}
audio_devices_t SwAudioOutputDescriptor::device() const
@@ -609,20 +598,11 @@
{
}
-status_t HwAudioOutputDescriptor::dump(int fd)
+void HwAudioOutputDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- AudioOutputDescriptor::dump(fd);
-
- snprintf(buffer, SIZE, "Source:\n");
- result.append(buffer);
- write(fd, result.string(), result.size());
- mSource->dump(fd, 0, 0);
-
- return NO_ERROR;
+ AudioOutputDescriptor::dump(dst);
+ dst->append("Source:\n");
+ mSource->dump(dst, 0, 0);
}
audio_devices_t HwAudioOutputDescriptor::supportedDevices()
@@ -792,20 +772,13 @@
return 0;
}
-status_t SwAudioOutputCollection::dump(int fd) const
+void SwAudioOutputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nOutputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nOutputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Output %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
// HwAudioOutputCollection implementation
@@ -837,20 +810,13 @@
return false;
}
-status_t HwAudioOutputCollection::dump(int fd) const
+void HwAudioOutputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nOutputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nOutputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Output %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index e78e121..cd1c2f2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -34,34 +34,29 @@
{
}
-static String8 dumpPatchEndpoints(
- int spaces, const char *prefix, int count, const audio_port_config *cfgs)
+static void dumpPatchEndpoints(
+ String8 *dst, int spaces, const char *prefix, int count, const audio_port_config *cfgs)
{
- String8 result;
for (int i = 0; i < count; ++i) {
const audio_port_config &cfg = cfgs[i];
- result.appendFormat("%*s [%s %d] ", spaces, "", prefix, i + 1);
+ dst->appendFormat("%*s [%s %d] ", spaces, "", prefix, i + 1);
if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
std::string device;
deviceToString(cfg.ext.device.type, device);
- result.appendFormat("Device ID %d %s", cfg.id, device.c_str());
+ dst->appendFormat("Device ID %d %s", cfg.id, device.c_str());
} else {
- result.appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
+ dst->appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
}
- result.append("\n");
+ dst->append("\n");
}
- return result;
}
-status_t AudioPatch::dump(int fd, int spaces, int index) const
+void AudioPatch::dump(String8 *dst, int spaces, int index) const
{
- String8 result;
- result.appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
+ dst->appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
spaces, "", index + 1, mUid, mHandle, mAfPatchHandle);
- result.append(dumpPatchEndpoints(spaces, "src ", mPatch.num_sources, mPatch.sources));
- result.append(dumpPatchEndpoints(spaces, "sink", mPatch.num_sinks, mPatch.sinks));
- write(fd, result.string(), result.size());
- return NO_ERROR;
+ dumpPatchEndpoints(dst, spaces, "src ", mPatch.num_sources, mPatch.sources);
+ dumpPatchEndpoints(dst, spaces, "sink", mPatch.num_sinks, mPatch.sinks);
}
status_t AudioPatchCollection::addAudioPatch(audio_patch_handle_t handle,
@@ -142,16 +137,12 @@
return NO_ERROR;
}
-status_t AudioPatchCollection::dump(int fd) const
+void AudioPatchCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "\nAudio Patches:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nAudio Patches:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 08930f1..3cf8014 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -52,64 +52,55 @@
return &mMix;
}
-status_t AudioPolicyMix::dump(int fd, int spaces, int index) const
+void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sAudio Policy Mix %d:\n", spaces, "", index+1);
- result.append(buffer);
+ dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
std::string mixTypeLiteral;
if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
+
std::string routeFlagLiteral;
RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
- snprintf(buffer, SIZE, "%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
+
std::string deviceLiteral;
deviceToString(mMix.mDeviceType, deviceLiteral);
- snprintf(buffer, SIZE, "%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
- result.append(buffer);
+ dst->appendFormat("%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
+
+ dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
int indexCriterion = 0;
for (const auto &criterion : mMix.mCriteria) {
- snprintf(buffer, SIZE, "%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
- result.append(buffer);
+ dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
+
std::string usageLiteral;
if (!UsageTypeConverter::toString(criterion.mValue.mUsage, usageLiteral)) {
ALOGE("%s: failed to convert usage %d", __FUNCTION__, criterion.mValue.mUsage);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
+
if (mMix.mMixType == MIX_TYPE_RECORDERS) {
std::string sourceLiteral;
if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
+
}
- snprintf(buffer, SIZE, "%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
- result.append(buffer);
+ dst->appendFormat("%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
+
std::string ruleLiteral;
if (!RuleTypeConverter::toString(criterion.mRule, ruleLiteral)) {
ALOGE("%s: failed to convert source %d", __FUNCTION__,criterion.mRule);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
}
- write(fd, result.string(), result.size());
- return NO_ERROR;
}
status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
@@ -349,14 +340,12 @@
return NO_ERROR;
}
-status_t AudioPolicyMixCollection::dump(int fd) const
+void AudioPolicyMixCollection::dump(String8 *dst) const
{
- std::string log("\nAudio Policy Mix:\n");
- write(fd, log.c_str(), log.size());
+ dst->append("\nAudio Policy Mix:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 3fe37ab..19dde6a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -354,26 +354,18 @@
return mGains[index]->checkConfig(gainConfig);
}
-void AudioPort::dump(int fd, int spaces, bool verbose) const
+void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
if (!mName.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
- result.append(buffer);
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
if (verbose) {
- mProfiles.dump(fd, spaces);
+ mProfiles.dump(dst, spaces);
if (mGains.size() != 0) {
- snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
- result = buffer;
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*s- gains:\n", spaces, "");
for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
+ mGains[i]->dump(dst, spaces + 2, i);
}
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index d04beec..a645e02 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -253,47 +253,35 @@
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
-void AudioProfile::dump(int fd, int spaces) const
+void AudioProfile::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : "");
- result.append(buffer);
if (mName.length() != 0) {
- snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
- result.append(buffer);
+ dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
- snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
}
if (!mSamplingRates.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- sampling rates:", spaces, "");
for (size_t i = 0; i < mSamplingRates.size(); i++) {
- snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
- result.append(buffer);
- result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+ dst->appendFormat("%d", mSamplingRates[i]);
+ dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
}
- result.append("\n");
+ dst->append("\n");
}
if (!mChannelMasks.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- channel masks:", spaces, "");
for (size_t i = 0; i < mChannelMasks.size(); i++) {
- snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
- result.append(buffer);
- result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+ dst->appendFormat("0x%04x", mChannelMasks[i]);
+ dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
}
- result.append("\n");
+ dst->append("\n");
}
- write(fd, result.string(), result.size());
}
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
@@ -559,17 +547,12 @@
}
}
-void AudioProfileVector::dump(int fd, int spaces) const
+void AudioProfileVector::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("%*s- Profiles:\n", spaces, "");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, spaces + 8);
+ dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
+ itemAt(i)->dump(dst, spaces + 8);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79ad1f7..c1fe5b0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -24,29 +24,17 @@
namespace android
{
-void AudioRoute::dump(int fd, int spaces) const
+void AudioRoute::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
- result.append(buffer);
-
- snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
- result.append(buffer);
-
+ dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+ dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
if (mSources.size() != 0) {
- snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- Sources: \n", spaces, "");
for (size_t i = 0; i < mSources.size(); i++) {
- snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
- result.append(buffer);
+ dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
}
}
- result.append("\n");
-
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index c237cef..815612d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -30,21 +30,6 @@
namespace android {
-status_t ClientDescriptor::dump(int fd, int spaces, int index)
-{
- String8 out;
-
- // FIXME: use until other descriptor classes have a dump to String8 method
- mDumpFd = fd;
-
- status_t status = dump(out, spaces, index);
- if (status == NO_ERROR) {
- write(fd, out.string(), out.size());
- }
-
- return status;
-}
-
std::string ClientDescriptor::toShortString() const
{
std::stringstream ss;
@@ -53,25 +38,21 @@
return ss.str();
}
-status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+void ClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
- out.appendFormat("%*s- Port Id: %d Session Id: %d UID: %d\n", spaces, "",
+ dst->appendFormat("%*sClient %d:\n", spaces, "", index+1);
+ dst->appendFormat("%*s- Port Id: %d Session Id: %d UID: %d\n", spaces, "",
mPortId, mSessionId, mUid);
- out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
+ dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
- out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
- out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
- return NO_ERROR;
+ dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+ dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
}
-status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+void TrackClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- ClientDescriptor::dump(out, spaces, index);
-
- out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
-
- return NO_ERROR;
+ ClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
}
std::string TrackClientDescriptor::toShortString() const
@@ -82,13 +63,10 @@
return ss.str();
}
-status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
+void RecordClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- ClientDescriptor::dump(out, spaces, index);
-
- out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
-
- return NO_ERROR;
+ ClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
}
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
@@ -112,31 +90,19 @@
mHwOutput = hwOutput;
}
-status_t SourceClientDescriptor::dump(String8& out, int spaces, int index)
+void SourceClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- TrackClientDescriptor::dump(out, spaces, index);
-
- if (mDumpFd >= 0) {
- out.appendFormat("%*s- Device:\n", spaces, "");
- write(mDumpFd, out.string(), out.size());
-
- mSrcDevice->dump(mDumpFd, 2, 0);
- mDumpFd = -1;
- }
-
- return NO_ERROR;
+ TrackClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Device:\n", spaces, "");
+ mSrcDevice->dump(dst, 2, 0);
}
-status_t SourceClientCollection::dump(int fd) const
+void SourceClientCollection::dump(String8 *dst) const
{
- String8 out;
- out.append("\nAudio sources:\n");
- write(fd, out.string(), out.size());
+ dst->append("\nAudio sources:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1638645..a9f7220 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -199,20 +199,15 @@
return nullptr;
}
-status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
+void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
{
if (isEmpty()) {
- return NO_ERROR;
+ return;
}
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- %s devices:\n", spaces, "", tag.string());
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("%*s- %s devices:\n", spaces, "", tag.string());
for (size_t i = 0; i < size(); i++) {
- itemAt(i)->dump(fd, spaces + 2, i, verbose);
+ itemAt(i)->dump(dst, spaces + 2, i, verbose);
}
- return NO_ERROR;
}
void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -269,35 +264,23 @@
port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
-status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sDevice %d:\n", spaces, "", index+1);
- result.append(buffer);
+ dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
if (mId != 0) {
- snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
- result.append(buffer);
+ dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
}
if (!mTagName.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
- result.append(buffer);
+ dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
}
std::string deviceLiteral;
if (deviceToString(mDeviceType, deviceLiteral)) {
- snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
}
if (mAddress.size() != 0) {
- snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
- result.append(buffer);
+ dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
}
- write(fd, result.string(), result.size());
- AudioPort::dump(fd, spaces, verbose);
-
- return NO_ERROR;
+ AudioPort::dump(dst, spaces, verbose);
}
void DeviceDescriptor::log() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 7b2341e..8bbb798 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -22,25 +22,13 @@
namespace android {
-status_t EffectDescriptor::dump(int fd)
+void EffectDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " I/O: %d\n", mIo);
- result.append(buffer);
- snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
- result.append(buffer);
- snprintf(buffer, SIZE, " Session: %d\n", mSession);
- result.append(buffer);
- snprintf(buffer, SIZE, " Name: %s\n", mDesc.name);
- result.append(buffer);
- snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
- result.append(buffer);
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
+ dst->appendFormat(" I/O: %d\n", mIo);
+ dst->appendFormat(" Strategy: %d\n", mStrategy);
+ dst->appendFormat(" Session: %d\n", mSession);
+ dst->appendFormat(" Name: %s\n", mDesc.name);
+ dst->appendFormat(" %s\n", mEnabled ? "Enabled" : "Disabled");
}
EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -174,24 +162,16 @@
return MAX_EFFECTS_MEMORY;
}
-status_t EffectDescriptorCollection::dump(int fd)
+void EffectDescriptorCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE,
+ dst->appendFormat(
"\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB, Max memory used: %d KB\n",
(float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory, mTotalEffectsMemoryMaxUsed);
- write(fd, buffer, strlen(buffer));
-
- snprintf(buffer, SIZE, "Registered effects:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("Registered effects:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Effect %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Effect %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index dcc0ec8..92bc595 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -218,37 +218,27 @@
mHandle = handle;
}
-void HwModule::dump(int fd)
+void HwModule::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " - name: %s\n", getName());
- result.append(buffer);
- snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, " - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
- result.append(buffer);
- write(fd, result.string(), result.size());
+ dst->appendFormat(" - name: %s\n", getName());
+ dst->appendFormat(" - handle: %d\n", mHandle);
+ dst->appendFormat(" - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
if (mOutputProfiles.size()) {
- write(fd, " - outputs:\n", strlen(" - outputs:\n"));
+ dst->append(" - outputs:\n");
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " output %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- mOutputProfiles[i]->dump(fd);
+ dst->appendFormat(" output %zu:\n", i);
+ mOutputProfiles[i]->dump(dst);
}
}
if (mInputProfiles.size()) {
- write(fd, " - inputs:\n", strlen(" - inputs:\n"));
+ dst->append(" - inputs:\n");
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " input %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- mInputProfiles[i]->dump(fd);
+ dst->appendFormat(" input %zu:\n", i);
+ mInputProfiles[i]->dump(dst);
}
}
- mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
- mRoutes.dump(fd, 2);
+ mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
+ mRoutes.dump(dst, 2);
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -301,19 +291,13 @@
return devDesc;
}
-status_t HwModuleCollection::dump(int fd) const
+void HwModuleCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nHW Modules dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nHW Modules dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd);
+ dst->appendFormat("- HW Module %zu:\n", i + 1);
+ itemAt(i)->dump(dst);
}
- return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fbc2384..8660624 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -108,16 +108,11 @@
return true;
}
-void IOProfile::dump(int fd)
+void IOProfile::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
+ AudioPort::dump(dst, 4);
- AudioPort::dump(fd, 4);
-
- snprintf(buffer, SIZE, " - flags: 0x%04x", getFlags());
- result.append(buffer);
+ dst->appendFormat(" - flags: 0x%04x", getFlags());
std::string flagsLiteral;
if (getRole() == AUDIO_PORT_ROLE_SINK) {
InputFlagConverter::maskToString(getFlags(), flagsLiteral);
@@ -125,21 +120,14 @@
OutputFlagConverter::maskToString(getFlags(), flagsLiteral);
}
if (!flagsLiteral.empty()) {
- result.appendFormat(" (%s)", flagsLiteral.c_str());
+ dst->appendFormat(" (%s)", flagsLiteral.c_str());
}
- result.append("\n");
- write(fd, result.string(), result.size());
- mSupportedDevices.dump(fd, String8("Supported"), 4, false);
-
- result.clear();
- snprintf(buffer, SIZE, "\n - maxOpenCount: %u - curOpenCount: %u\n",
+ dst->append("\n");
+ mSupportedDevices.dump(dst, String8("Supported"), 4, false);
+ dst->appendFormat("\n - maxOpenCount: %u - curOpenCount: %u\n",
maxOpenCount, curOpenCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " - maxActiveCount: %u - curActiveCount: %u\n",
+ dst->appendFormat(" - maxActiveCount: %u - curActiveCount: %u\n",
maxActiveCount, curActiveCount);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
}
void IOProfile::log()
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index 65649fb..c311a4f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -79,24 +79,16 @@
mVolumeCurve[deviceCategory] = point;
}
-void StreamDescriptor::dump(int fd) const
+void StreamDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%s %02d %02d ",
+ dst->appendFormat("%s %02d %02d ",
mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
- result.append(buffer);
for (size_t i = 0; i < mIndexCur.size(); i++) {
- snprintf(buffer, SIZE, "%04x : %02d, ",
+ dst->appendFormat("%04x : %02d, ",
mIndexCur.keyAt(i),
mIndexCur.valueAt(i));
- result.append(buffer);
}
- result.append("\n");
-
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
StreamDescriptorCollection::StreamDescriptorCollection()
@@ -204,23 +196,15 @@
}
}
-status_t StreamDescriptorCollection::dump(int fd) const
+void StreamDescriptorCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nStreams dump:\n");
- write(fd, buffer, strlen(buffer));
- snprintf(buffer, SIZE,
+ dst->append("\nStreams dump:\n");
+ dst->append(
" Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
- write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, " %02zu ", i);
- write(fd, buffer, strlen(buffer));
- valueAt(i).dump(fd);
+ dst->appendFormat(" %02zu ", i);
+ valueAt(i).dump(dst);
}
-
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
index ac3f1bc..620f361 100644
--- a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -68,81 +68,56 @@
return decibels;
}
-void VolumeCurve::dump(int fd) const
+void VolumeCurve::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, " {");
- result.append(buffer);
+ dst->append(" {");
for (size_t i = 0; i < mCurvePoints.size(); i++) {
- snprintf(buffer, SIZE, "(%3d, %5d)",
+ dst->appendFormat("(%3d, %5d)",
mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
- result.append(buffer);
- result.append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
+ dst->append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
}
- write(fd, result.string(), result.size());
}
-void VolumeCurvesForStream::dump(int fd, int spaces = 0, bool curvePoints) const
+void VolumeCurvesForStream::dump(String8 *dst, int spaces = 0, bool curvePoints) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
if (!curvePoints) {
- snprintf(buffer, SIZE, "%s %02d %02d ",
+ dst->appendFormat("%s %02d %02d ",
mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
- result.append(buffer);
for (size_t i = 0; i < mIndexCur.size(); i++) {
- snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
- result.append(buffer);
+ dst->appendFormat("%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
return;
}
for (size_t i = 0; i < size(); i++) {
std::string deviceCatLiteral;
DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
- snprintf(buffer, SIZE, "%*s %s :",
+ dst->appendFormat("%*s %s :",
spaces, "", deviceCatLiteral.c_str());
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ valueAt(i)->dump(dst);
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
-status_t VolumeCurvesCollection::dump(int fd) const
+void VolumeCurvesCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nStreams dump:\n");
- write(fd, buffer, strlen(buffer));
- snprintf(buffer, SIZE,
+ dst->append("\nStreams dump:\n");
+ dst->append(
" Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
- write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, " %02zu ", i);
- write(fd, buffer, strlen(buffer));
- valueAt(i).dump(fd);
+ dst->appendFormat(" %02zu ", i);
+ valueAt(i).dump(dst);
}
- snprintf(buffer, SIZE, "\nVolume Curves for Use Cases (aka Stream types) dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nVolume Curves for Use Cases (aka Stream types) dump:\n");
for (size_t i = 0; i < size(); i++) {
std::string streamTypeLiteral;
StreamTypeConverter::toString(keyAt(i), streamTypeLiteral);
- snprintf(buffer, SIZE,
+ dst->appendFormat(
" %s (%02zu): Curve points for device category (index, attenuation in millibel)\n",
streamTypeLiteral.c_str(), i);
- write(fd, buffer, strlen(buffer));
- valueAt(i).dump(fd, 2, true);
+ valueAt(i).dump(dst, 2, true);
}
-
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index c76326a..69395f3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -186,6 +186,7 @@
return STRATEGY_DTMF;
default:
ALOGE("unknown stream type %d", stream);
+ FALLTHROUGH_INTENDED;
case AUDIO_STREAM_SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e28ab68..58acad3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2666,53 +2666,53 @@
return res;
}
-
-status_t AudioPolicyManager::dump(int fd)
+void AudioPolicyManager::dump(String8 *dst) const
{
- String8 result;
- result.appendFormat("\nAudioPolicyManager Dump: %p\n", this);
- result.appendFormat(" Primary Output: %d\n",
+ dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
+ dst->appendFormat(" Primary Output: %d\n",
hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
std::string stateLiteral;
AudioModeConverter::toString(mEngine->getPhoneState(), stateLiteral);
- result.appendFormat(" Phone state: %s\n", stateLiteral.c_str());
+ dst->appendFormat(" Phone state: %s\n", stateLiteral.c_str());
const char* forceUses[AUDIO_POLICY_FORCE_USE_CNT] = {
"communications", "media", "record", "dock", "system",
"HDMI system audio", "encoded surround output", "vibrate ringing" };
for (audio_policy_force_use_t i = AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
i < AUDIO_POLICY_FORCE_USE_CNT; i = (audio_policy_force_use_t)((int)i + 1)) {
- result.appendFormat(" Force use for %s: %d\n",
+ dst->appendFormat(" Force use for %s: %d\n",
forceUses[i], mEngine->getForceUse(i));
}
- result.appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
- result.appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
- result.appendFormat(" Config source: %s\n", getConfig().getSource().c_str());
- write(fd, result.string(), result.size());
-
- mAvailableOutputDevices.dump(fd, String8("Available output"));
- mAvailableInputDevices.dump(fd, String8("Available input"));
- mHwModulesAll.dump(fd);
- mOutputs.dump(fd);
- mInputs.dump(fd);
- mVolumeCurves->dump(fd);
- mEffects.dump(fd);
- mAudioPatches.dump(fd);
- mPolicyMixes.dump(fd);
- mAudioSources.dump(fd);
-
+ dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
+ dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
+ dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const
+ mAvailableOutputDevices.dump(dst, String8("Available output"));
+ mAvailableInputDevices.dump(dst, String8("Available input"));
+ mHwModulesAll.dump(dst);
+ mOutputs.dump(dst);
+ mInputs.dump(dst);
+ mVolumeCurves->dump(dst);
+ mEffects.dump(dst);
+ mAudioPatches.dump(dst);
+ mPolicyMixes.dump(dst);
+ mAudioSources.dump(dst);
if (!mSurroundFormats.empty()) {
- result = String8("\nEnabled Surround Formats:\n");
+ dst->append("\nEnabled Surround Formats:\n");
size_t i = 0;
for (const auto& fmt : mSurroundFormats) {
- result.append(i++ == 0 ? " " : ", ");
+ dst->append(i++ == 0 ? " " : ", ");
std::string sfmt;
FormatConverter::toString(fmt, sfmt);
- result.appendFormat("%s", sfmt.c_str());
+ dst->append(sfmt.c_str());
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
+}
+status_t AudioPolicyManager::dump(int fd)
+{
+ String8 result;
+ dump(&result);
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -5897,6 +5897,7 @@
case AUDIO_FORMAT_DOLBY_TRUEHD:
case AUDIO_FORMAT_E_AC3_JOC:
mSurroundFormats.insert(format);
+ break;
default:
break;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index fcb9d25..f559b7f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -186,7 +186,9 @@
virtual bool isSourceActive(audio_source_t source) const;
- virtual status_t dump(int fd);
+ void dump(String8 *dst) const; // helper for dump(int fd)
+
+ status_t dump(int fd) override;
virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index c250628..ab4971d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -38,6 +38,10 @@
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
namespace android {
using namespace camera2;
@@ -951,7 +955,7 @@
case Parameters::VIDEO_SNAPSHOT:
case Parameters::STILL_CAPTURE:
mCaptureSequencer->waitUntilIdle(kStopCaptureTimeout);
- // no break
+ FALLTHROUGH_INTENDED;
case Parameters::RECORD:
case Parameters::PREVIEW:
syncWithDevice();
@@ -981,7 +985,7 @@
"stop preview: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
}
- // no break
+ FALLTHROUGH_INTENDED;
case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::STOPPED;
@@ -1806,7 +1810,7 @@
switch (newState) {
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
success = true;
- // no break
+ FALLTHROUGH_INTENDED;
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
sendCompletedMessage = true;
l.mParameters.currentAfTriggerId = -1;
@@ -1830,7 +1834,7 @@
switch (newState) {
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
success = true;
- // no break
+ FALLTHROUGH_INTENDED;
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
// Don't send notifications upstream if they're not for
// the current AF trigger. For example, if cancel was
@@ -1858,7 +1862,7 @@
case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
// Start passive scan, inform upstream
afInMotion = true;
- // no break
+ FALLTHROUGH_INTENDED;
case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
// Stop passive scan, inform upstream
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f42cdd3..97f7fdc 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -551,9 +551,11 @@
return DONE;
}
- if (l.mParameters.isDeviceZslSupported) {
+ if ((l.mParameters.isDeviceZslSupported) && (l.mParameters.state != Parameters::RECORD) &&
+ (l.mParameters.state != Parameters::VIDEO_SNAPSHOT)) {
// If device ZSL is supported, drop all pending preview buffers to reduce the chance of
// rendering preview frames newer than the still frame.
+ // Additionally, preview must not get interrupted during video recording.
client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index dd2ef99..6da05c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -123,6 +123,7 @@
physicalKeysEntry.data.i32 + physicalKeysEntry.count);
}
+ mProviderManager = providerPtr;
return OK;
}
@@ -627,12 +628,11 @@
if (physicalCameraId.size() > 0) {
std::vector<std::string> physicalCameraIds;
- std::string physicalId(physicalCameraId.string());
bool logicalCamera =
- CameraProviderManager::isLogicalCamera(mDevice->info(), &physicalCameraIds);
+ mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
if (!logicalCamera ||
- std::find(physicalCameraIds.begin(), physicalCameraIds.end(), physicalId) ==
- physicalCameraIds.end()) {
+ std::find(physicalCameraIds.begin(), physicalCameraIds.end(),
+ physicalCameraId.string()) == physicalCameraIds.end()) {
String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.",
mCameraIdStr.string(), physicalCameraId.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index c30561d..09ce977 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -301,6 +301,7 @@
std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap;
static const int32_t MAX_SURFACES_PER_STREAM = 2;
+ sp<CameraProviderManager> mProviderManager;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index c4944a6..a94e886 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -396,35 +396,46 @@
return ret;
}
-bool CameraProviderManager::isLogicalCamera(const CameraMetadata& staticInfo,
- std::vector<std::string>* physicalCameraIds) {
- bool isLogicalCam = false;
- camera_metadata_ro_entry_t entryCap;
+void CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds() {
+ camera_metadata_entry_t entryCap;
- entryCap = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
for (size_t i = 0; i < entryCap.count; ++i) {
uint8_t capability = entryCap.data.u8[i];
if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
- isLogicalCam = true;
+ mIsLogicalCamera = true;
break;
}
}
- if (!isLogicalCam) {
- return false;
+ if (!mIsLogicalCamera) {
+ return;
}
- camera_metadata_ro_entry_t entryIds = staticInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+ camera_metadata_entry_t entryIds = mCameraCharacteristics.find(
+ ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
const uint8_t* ids = entryIds.data.u8;
size_t start = 0;
for (size_t i = 0; i < entryIds.count; ++i) {
if (ids[i] == '\0') {
if (start != i) {
- physicalCameraIds->push_back((const char*)ids+start);
+ mPhysicalIds.push_back((const char*)ids+start);
}
start = i+1;
}
}
- return true;
+}
+
+bool CameraProviderManager::isLogicalCamera(const std::string& id,
+ std::vector<std::string>* physicalCameraIds) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return false;
+
+ if (deviceInfo->mIsLogicalCamera && physicalCameraIds != nullptr) {
+ *physicalCameraIds = deviceInfo->mPhysicalIds;
+ }
+ return deviceInfo->mIsLogicalCamera;
}
bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) {
@@ -449,9 +460,9 @@
}
std::vector<std::string> physicalIds;
- if (isLogicalCamera(info, &physicalIds)) {
- if (std::find(physicalIds.begin(), physicalIds.end(), cameraId) !=
- physicalIds.end()) {
+ if (deviceInfo->mIsLogicalCamera) {
+ if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
+ cameraId) != deviceInfo->mPhysicalIds.end()) {
int deviceVersion = HARDWARE_DEVICE_API_VERSION(
deviceInfo->mVersion.get_major(), deviceInfo->mVersion.get_minor());
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) {
@@ -760,9 +771,8 @@
}
// Dump characteristics of non-standalone physical camera
- std::vector<std::string> physicalIds;
- if (isLogicalCamera(info2, &physicalIds)) {
- for (auto& id : physicalIds) {
+ if (device->mIsLogicalCamera) {
+ for (auto& id : device->mPhysicalIds) {
// Skip if physical id is an independent camera
if (std::find(mProviderPublicCameraIds.begin(), mProviderPublicCameraIds.end(), id)
!= mProviderPublicCameraIds.end()) {
@@ -1130,6 +1140,7 @@
mHasFlashUnit = false;
}
+ queryPhysicalCameraIds();
// Get physical camera characteristics if applicable
auto castResult = device::V3_5::ICameraDevice::castFrom(mInterface);
if (!castResult.isOk()) {
@@ -1142,9 +1153,8 @@
return;
}
- std::vector<std::string> physicalIds;
- if (CameraProviderManager::isLogicalCamera(mCameraCharacteristics, &physicalIds)) {
- for (auto& id : physicalIds) {
+ if (mIsLogicalCamera) {
+ for (auto& id : mPhysicalIds) {
if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
mPublicCameraIds.end()) {
continue;
@@ -1622,20 +1632,14 @@
std::unordered_set<std::string> removedIds;
for (auto& deviceId : deviceIds) {
- CameraMetadata info;
- status_t res = getCameraCharacteristicsLocked(deviceId, &info);
- if (res != OK) {
- ALOGE("%s: Failed to getCameraCharacteristics for id %s", __FUNCTION__,
- deviceId.c_str());
- return;
- }
+ auto deviceInfo = findDeviceInfoLocked(deviceId);
+ if (deviceInfo == nullptr) continue;
- // idCombo contains the ids of a logical camera and its physical cameras
- std::vector<std::string> idCombo;
- bool logicalCamera = isLogicalCamera(info, &idCombo);
- if (!logicalCamera) {
+ if (!deviceInfo->mIsLogicalCamera) {
continue;
}
+ // idCombo contains the ids of a logical camera and its physical cameras
+ std::vector<std::string> idCombo = deviceInfo->mPhysicalIds;
idCombo.push_back(deviceId);
for (auto& id : deviceIds) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 61e21b4..9016747 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -231,11 +231,10 @@
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
/*
- * Check if a camera with staticInfo is a logical camera. And if yes, return
+ * Check if a camera is a logical camera. And if yes, return
* the physical camera ids.
*/
- static bool isLogicalCamera(const CameraMetadata& staticInfo,
- std::vector<std::string>* physicalCameraIds);
+ bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
bool isHiddenPhysicalCamera(const std::string& cameraId);
private:
@@ -293,6 +292,8 @@
const std::string mId; // ID section of full name
const hardware::hidl_version mVersion;
const metadata_vendor_id_t mProviderTagid;
+ bool mIsLogicalCamera;
+ std::vector<std::string> mPhysicalIds;
const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
@@ -319,7 +320,7 @@
const std::vector<std::string>& publicCameraIds,
const hardware::camera::common::V1_0::CameraResourceCost& resourceCost) :
mName(name), mId(id), mVersion(version), mProviderTagid(tagId),
- mResourceCost(resourceCost),
+ mIsLogicalCamera(false), mResourceCost(resourceCost),
mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
mHasFlashUnit(false), mPublicCameraIds(publicCameraIds) {}
virtual ~DeviceInfo();
@@ -383,6 +384,7 @@
private:
CameraMetadata mCameraCharacteristics;
std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
+ void queryPhysicalCameraIds();
};
private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6e61be2..53aee7e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -128,7 +128,7 @@
}
std::vector<std::string> physicalCameraIds;
- bool isLogical = CameraProviderManager::isLogicalCamera(mDeviceInfo, &physicalCameraIds);
+ bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
if (isLogical) {
for (auto& physicalId : physicalCameraIds) {
res = manager->getCameraCharacteristics(physicalId, &mPhysicalDeviceInfoMap[physicalId]);
@@ -2318,7 +2318,7 @@
return NULL;
}
}
- newRequest->mOutputSurfaces[i] = surfaces;
+ newRequest->mOutputSurfaces[streams.data.i32[i]] = surfaces;
}
// Lazy completion of stream configuration (allocation/registration)
@@ -4930,14 +4930,13 @@
res = outputStream->getBuffer(&outputBuffers->editItemAt(j),
waitDuration,
- captureRequest->mOutputSurfaces[j]);
+ captureRequest->mOutputSurfaces[outputStream->getId()]);
if (res != OK) {
// Can't get output buffer from gralloc queue - this could be due to
// abandoned queue or other consumer misbehavior, so not a fatal
// error
ALOGE("RequestThread: Can't get output buffer, skipping request:"
" %s (%d)", strerror(-res), res);
-
return TIMED_OUT;
}
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index db5f0ff..789548d 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -63,6 +63,59 @@
include $(BUILD_EXECUTABLE)
+####################################################################
+
+# service executable
+include $(CLEAR_VARS)
+# seccomp is not required for coverage build.
+ifneq ($(NATIVE_COVERAGE),true)
+LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
+LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
+endif
+LOCAL_SRC_FILES := \
+ main_swcodecservice.cpp \
+ MediaCodecUpdateService.cpp \
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+ $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(UBSAN_RUNTIME_LIBRARY) \
+ $(TSAN_RUNTIME_LIBRARY) \
+ $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(2ND_UBSAN_RUNTIME_LIBRARY) \
+ $(2ND_TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer: $(sanitizer_runtime_libraries))
+
+llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+ $(LLNDK_LIBRARIES)))
+
+# $(info LLNDK: $(llndk_libraries))
+
+LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
+
+LOCAL_SHARED_LIBRARIES := \
+ libavservices_minijail \
+ libbase \
+ libbinder \
+ libcutils \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libmedia \
+ libutils \
+ libziparchive \
+
+LOCAL_MODULE := mediaswcodec
+LOCAL_INIT_RC := mediaswcodec.rc
+LOCAL_32_BIT_ONLY := true
+
+sanitizer_runtime_libraries :=
+llndk_libraries :=
+
+include $(BUILD_EXECUTABLE)
+
+####################################################################
+
# service seccomp policy
ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
include $(CLEAR_VARS)
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
new file mode 100644
index 0000000..aee890d
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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_TAG "MediaCodecUpdateService"
+//#define LOG_NDEBUG 0
+
+#include <android/dlext.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/CodecServiceRegistrant.h>
+#include <utils/Log.h>
+#include <ziparchive/zip_archive.h>
+#include <cutils/properties.h>
+
+#include "MediaCodecUpdateService.h"
+
+// Copied from GraphicsEnv.cpp
+// TODO(b/37049319) Get this from a header once one exists
+extern "C" {
+ android_namespace_t* android_create_namespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ android_namespace_t* parent);
+ bool android_link_namespaces(android_namespace_t* from,
+ android_namespace_t* to,
+ const char* shared_libs_sonames);
+ enum {
+ ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+ };
+}
+
+namespace android {
+namespace media {
+
+binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
+ ALOGV("loadPlugins %s", apkPath.c_str());
+
+ ZipArchiveHandle zipHandle;
+ void *registrantLib = NULL;
+ int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+
+ if (ret == 0) {
+ char abilist32[PROPERTY_VALUE_MAX];
+ property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+
+ auto abis = base::Split(abilist32, ",");
+ if (abis.empty()) {
+ ALOGW("abilist is empty, trying armeabi-v7a ...");
+ abis.push_back("armeabi-v7a");
+ }
+
+ // TODO: Only try the first entry in abilist32 for now.
+ // We probably should try the next if it fails.
+ String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
+ String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
+ String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
+ String8 zipEntryPath = libPathInApk + "/libmedia_codecserviceregistrant.so";
+
+ ZipEntry entry;
+ ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
+
+ if (ret == 0) {
+ android_namespace_t *codecNs = android_create_namespace("codecs",
+ nullptr, // ld_library_path
+ defaultLibPath.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr, // permitted_when_isolated_path
+ nullptr); // parent
+
+ if (codecNs != nullptr) {
+ String8 linked_libraries(LINKED_LIBRARIES);
+ if (android_link_namespaces(
+ codecNs, nullptr, linked_libraries.c_str())) {
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = codecNs,
+ };
+
+ registrantLib = android_dlopen_ext(
+ libPath.string(),
+ RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+
+ if (registrantLib == NULL) {
+ ALOGE("Failed to load lib from archive: %s", dlerror());
+ }
+ } else {
+ ALOGE("Failed to link namespace");
+ }
+ } else {
+ ALOGE("Failed to create codec namespace");
+ }
+ } else {
+ ALOGE("Failed to find entry (ret=%d)", ret);
+ }
+
+ CloseArchive(zipHandle);
+ } else {
+ ALOGE("Failed to open archive (ret=%d)", ret);
+ }
+
+ if (registrantLib) {
+ RegisterCodecServicesFunc registerCodecServices =
+ reinterpret_cast<RegisterCodecServicesFunc>(
+ dlsym(registrantLib, "RegisterCodecServices"));
+ if (registerCodecServices) {
+ registerCodecServices();
+ } else {
+ LOG(WARNING) << "Cannot register codec services "
+ "-- corrupted library.";
+ }
+ } else {
+ LOG(ERROR) << "Cannot find codec service registrant.";
+ }
+
+ return binder::Status::ok();
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
new file mode 100644
index 0000000..7b7cee9
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * 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_MEDIA_CODEC_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaCodecUpdateService
+ : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
+{
+ friend class BinderService<MediaCodecUpdateService>;
+public:
+ MediaCodecUpdateService() : BnMediaUpdateService() { }
+ virtual ~MediaCodecUpdateService() { }
+ static const char* getServiceName() { return "media.codec.update"; }
+ binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+} // namespace media
+} // namespace android
+
+#endif // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 51619f6..6d47be6 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -48,37 +48,21 @@
::android::hardware::configureRpcThreadpool(64, false);
- // Registration of customized codec services
- void *registrantLib = dlopen(
- "libmedia_codecserviceregistrant.so",
- RTLD_NOW | RTLD_LOCAL);
- if (registrantLib) {
- RegisterCodecServicesFunc registerCodecServices =
- reinterpret_cast<RegisterCodecServicesFunc>(
- dlsym(registrantLib, "RegisterCodecServices"));
- if (registerCodecServices) {
- registerCodecServices();
- } else {
- LOG(WARNING) << "Cannot register additional services "
- "-- corrupted library.";
- }
+ // Default codec services
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmxStore> omxStore = new implementation::OmxStore();
+ if (omxStore == nullptr) {
+ LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+ } else if (omxStore->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+ }
+ sp<IOmx> omx = new implementation::Omx();
+ if (omx == nullptr) {
+ LOG(ERROR) << "Cannot create IOmx HAL service.";
+ } else if (omx->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmx HAL service.";
} else {
- // Default codec services
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- LOG(ERROR) << "Cannot create IOmxStore HAL service.";
- } else if (omxStore->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmxStore HAL service.";
- }
- sp<IOmx> omx = new implementation::Omx();
- if (omx == nullptr) {
- LOG(ERROR) << "Cannot create IOmx HAL service.";
- } else if (omx->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmx HAL service.";
- } else {
- LOG(INFO) << "IOmx HAL service created.";
- }
+ LOG(INFO) << "IOmx HAL service created.";
}
::android::hardware::joinRpcThreadpool();
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
new file mode 100644
index 0000000..386abb2
--- /dev/null
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -0,0 +1,74 @@
+/*
+**
+** 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 <android-base/logging.h>
+
+// from LOCAL_C_INCLUDES
+#include "minijail.h"
+
+#include <android-base/properties.h>
+#include <binder/ProcessState.h>
+#include <dlfcn.h>
+#include <hidl/HidlTransportSupport.h>
+#include <media/CodecServiceRegistrant.h>
+
+#include "MediaCodecUpdateService.h"
+
+using namespace android;
+
+// TODO: replace policy with software codec-only policies
+// Must match location in Android.mk.
+static const char kSystemSeccompPolicyPath[] =
+ "/system/etc/seccomp_policy/mediacodec.policy";
+static const char kVendorSeccompPolicyPath[] =
+ "/vendor/etc/seccomp_policy/mediacodec.policy";
+
+int main(int argc __unused, char** /*argv*/)
+{
+ LOG(INFO) << "media swcodec service starting";
+ signal(SIGPIPE, SIG_IGN);
+ SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
+
+ std::string value = base::GetProperty("ro.build.type", "unknown");
+ if (value == "userdebug" || value == "eng") {
+ media::MediaCodecUpdateService::instantiate();
+ }
+
+ android::ProcessState::self()->startThreadPool();
+
+ ::android::hardware::configureRpcThreadpool(64, false);
+
+ // Registration of customized codec services
+ void *registrantLib = dlopen(
+ "libmedia_codecserviceregistrant.so",
+ RTLD_NOW | RTLD_LOCAL);
+ if (registrantLib) {
+ RegisterCodecServicesFunc registerCodecServices =
+ reinterpret_cast<RegisterCodecServicesFunc>(
+ dlsym(registrantLib, "RegisterCodecServices"));
+ if (registerCodecServices) {
+ registerCodecServices();
+ } else {
+ LOG(WARNING) << "Cannot register codec services "
+ "-- corrupted library.";
+ }
+ } else {
+ LOG(ERROR) << "Cannot find codec service registrant.";
+ }
+
+ ::android::hardware::joinRpcThreadpool();
+}
diff --git a/services/mediacodec/mediaswcodec.rc b/services/mediacodec/mediaswcodec.rc
new file mode 100644
index 0000000..dfe3381
--- /dev/null
+++ b/services/mediacodec/mediaswcodec.rc
@@ -0,0 +1,6 @@
+service media.swcodec /system/bin/mediaswcodec
+ class main
+ user mediacodec
+ group camera drmrpc mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
index 4115f6d..ea34c9d 100644
--- a/services/mediaextractor/MediaExtractorUpdateService.h
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -18,17 +18,17 @@
#define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
#include <binder/BinderService.h>
-#include <android/media/BnMediaExtractorUpdateService.h>
+#include <android/media/BnMediaUpdateService.h>
namespace android {
namespace media {
class MediaExtractorUpdateService
- : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+ : public BinderService<MediaExtractorUpdateService>, public BnMediaUpdateService
{
friend class BinderService<MediaExtractorUpdateService>;
public:
- MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+ MediaExtractorUpdateService() : BnMediaUpdateService() { }
virtual ~MediaExtractorUpdateService() { }
static const char* getServiceName() { return "media.extractor.update"; }
binder::Status loadPlugins(const ::std::string& apkPath);
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 53ee145..5ec997c 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -58,7 +58,7 @@
if (!dumpAllowed()) {
std::stringstream ss;
- ss << "Permission denial: can't dump AAudioService from pid="
+ ss << "Permission Denial: can't dump AAudioService from pid="
<< IPCThreadState::self()->getCallingPid() << ", uid="
<< IPCThreadState::self()->getCallingUid() << "\n";
result = ss.str();
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 253f290..a134a13 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -77,6 +77,13 @@
*/
virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
+ /**
+ * Set time that the associated frame was presented to the hardware.
+ *
+ * @param positionFrames receive position, input value is ignored
+ * @param timeNanos receive time, input value is ignored
+ * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error
+ */
virtual aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
int32_t getFramesPerBurst() const {
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index a7cd128..2f1ec7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -193,5 +193,13 @@
aaudio_result_t AAudioServiceEndpointShared::getTimestamp(int64_t *positionFrames,
int64_t *timeNanos) {
- return mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
+ aaudio_result_t result = mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
+ if (result == AAUDIO_ERROR_INVALID_STATE) {
+ // getTimestamp() can return AAUDIO_ERROR_INVALID_STATE if the stream has
+ // not completely started. This can cause a race condition that kills the
+ // timestamp service thread. So we reduce the error to a less serious one
+ // that allows the timestamp thread to continue.
+ result = AAUDIO_ERROR_UNAVAILABLE;
+ }
+ return result;
}
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 3c7d29d..65f1a44 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -55,6 +55,7 @@
libaudiohal_deathhandler \
android.hardware.soundtrigger@2.0 \
android.hardware.soundtrigger@2.1 \
+ android.hardware.soundtrigger@2.2 \
android.hardware.audio.common@2.0 \
android.hidl.allocator@1.0 \
android.hidl.memory@1.0
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index adf252e..0f9aa15 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -356,6 +356,50 @@
return hidlReturn;
}
+int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle,
+ struct sound_trigger_recognition_event** event)
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
+ if (soundtrigger_2_2 == 0) {
+ ALOGE("getModelState not supported");
+ return -ENODEV;
+ }
+
+ sp<SoundModel> model = getModel(handle);
+ if (model == 0) {
+ ALOGE("getModelState model not found for handle %u", handle);
+ return -EINVAL;
+ }
+
+ int ret = NO_ERROR;
+ Return<void> hidlReturn;
+ {
+ AutoMutex lock(mHalLock);
+ hidlReturn = soundtrigger_2_2->getModelState(
+ model->mHalHandle,
+ [&](int r, const V2_0_ISoundTriggerHwCallback::RecognitionEvent& halEvent) {
+ ret = r;
+ if (ret != 0) {
+ ALOGE("getModelState returned error code %d", ret);
+ } else {
+ *event = convertRecognitionEventFromHal(&halEvent);
+ }
+ });
+ }
+ if (!hidlReturn.isOk()) {
+ ALOGE("getModelState error %s", hidlReturn.description().c_str());
+ free(*event);
+ *event = nullptr;
+ ret = FAILED_TRANSACTION;
+ }
+ return ret;
+}
+
SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
: mModuleName(moduleName), mNextUniqueId(1)
{
@@ -388,6 +432,12 @@
return castResult_2_1.isOk() ? static_cast<sp<V2_1_ISoundTriggerHw>>(castResult_2_1) : nullptr;
}
+sp<V2_2_ISoundTriggerHw> SoundTriggerHalHidl::toService2_2(const sp<ISoundTriggerHw>& s)
+{
+ auto castResult_2_2 = V2_2_ISoundTriggerHw::castFrom(s);
+ return castResult_2_2.isOk() ? static_cast<sp<V2_2_ISoundTriggerHw>>(castResult_2_2) : nullptr;
+}
+
sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
{
AutoMutex lock(mLock);
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index 0b44ae0..3f4bec3 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -27,6 +27,7 @@
#include "SoundTriggerHalInterface.h"
#include <android/hardware/soundtrigger/2.0/types.h>
#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
#include <android/hardware/soundtrigger/2.1/ISoundTriggerHwCallback.h>
@@ -46,6 +47,8 @@
using V2_1_ISoundTriggerHwCallback =
::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
using ::android::hidl::memory::V1_0::IMemory;
+using V2_2_ISoundTriggerHw =
+ ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
class SoundTriggerHalHidl : public SoundTriggerHalInterface,
public virtual V2_1_ISoundTriggerHwCallback
@@ -92,6 +95,14 @@
*/
virtual int stopAllRecognitions();
+ /* Get the current state of a given model.
+ * Returns 0 or an error code. If successful it also sets indicated the event pointer
+ * and expectes that the caller will free the memory.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+ */
+ virtual int getModelState(sound_model_handle_t handle,
+ struct sound_trigger_recognition_event** event);
+
// ISoundTriggerHwCallback
virtual ::android::hardware::Return<void> recognitionCallback(
const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
@@ -182,6 +193,7 @@
uint32_t nextUniqueId();
sp<ISoundTriggerHw> getService();
sp<V2_1_ISoundTriggerHw> toService2_1(const sp<ISoundTriggerHw>& s);
+ sp<V2_2_ISoundTriggerHw> toService2_2(const sp<ISoundTriggerHw>& s);
sp<SoundModel> getModel(sound_model_handle_t handle);
sp<SoundModel> removeModel(sound_model_handle_t handle);
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
index c083195..076ca23 100644
--- a/services/soundtrigger/SoundTriggerHalInterface.h
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -71,6 +71,14 @@
*/
virtual int stopAllRecognitions() = 0;
+ /* Get the current state of a given model.
+ * Returns 0 or an error code. If successful it also sets indicated the event pointer
+ * and expectes that the caller will free the memory.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+ */
+ virtual int getModelState(sound_model_handle_t handle,
+ struct sound_trigger_recognition_event** event) = 0;
+
protected:
SoundTriggerHalInterface() {}
};
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index eb9cd1d..79e9e88 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -717,6 +717,40 @@
return NO_ERROR;
}
+status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory)
+{
+ ALOGV("getModelState() model handle %d", handle);
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
+ AutoMutex lock(mLock);
+ sp<Model> model = getModel(handle);
+ if (model == 0) {
+ return BAD_VALUE;
+ }
+
+ if (model->mState != Model::STATE_ACTIVE) {
+ return INVALID_OPERATION;
+ }
+
+ if (model->mType != SOUND_MODEL_TYPE_GENERIC) {
+ return BAD_VALUE;
+ }
+
+ struct sound_trigger_recognition_event* event = nullptr;
+ status_t status = mHalInterface->getModelState(handle, &event);
+ if (status == NO_ERROR) {
+ sp<SoundTriggerHwService> service;
+ service = mService.promote();
+ if (service != 0) {
+ eventMemory = service->prepareRecognitionEvent(event);
+ }
+ free(event);
+ }
+ return status;
+}
+
void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
{
ALOGV("onCallbackEvent type %d", event->mType);
@@ -1018,6 +1052,22 @@
return module->stopRecognition(handle);
}
+status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory)
+{
+ ALOGV("getModelState() model handle %d", handle);
+ if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid())) {
+ return PERMISSION_DENIED;
+ }
+
+ sp<Module> module = mModule.promote();
+ if (module == 0) {
+ return NO_INIT;
+ }
+ return module->getModelState(handle, eventMemory);
+}
+
void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
{
ALOGV("ModuleClient::setCaptureState_l %d", active);
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 708fc98..c222cd9 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -122,6 +122,8 @@
virtual status_t startRecognition(sound_model_handle_t handle,
const sp<IMemory>& dataMemory);
virtual status_t stopRecognition(sound_model_handle_t handle);
+ virtual status_t getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory);
sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
@@ -169,6 +171,8 @@
virtual status_t startRecognition(sound_model_handle_t handle,
const sp<IMemory>& dataMemory);
virtual status_t stopRecognition(sound_model_handle_t handle);
+ virtual status_t getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory);
virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
index 25332a4..32882f1 100644
--- a/soundtrigger/ISoundTrigger.cpp
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -32,6 +32,7 @@
UNLOAD_SOUND_MODEL,
START_RECOGNITION,
STOP_RECOGNITION,
+ GET_MODEL_STATE,
};
class BpSoundTrigger: public BpInterface<ISoundTrigger>
@@ -113,6 +114,22 @@
return status;
}
+ virtual status_t getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+ data.write(&handle, sizeof(sound_model_handle_t));
+ status_t status = remote()->transact(GET_MODEL_STATE, data, &reply);
+ if (status == NO_ERROR) {
+ status = (status_t)reply.readInt32();
+ if (status == NO_ERROR) {
+ eventMemory = interface_cast<IMemory>(reply.readStrongBinder());
+ }
+ }
+ return status;
+ }
+
};
IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger");
@@ -169,6 +186,24 @@
reply->writeInt32(status);
return NO_ERROR;
}
+ case GET_MODEL_STATE: {
+ CHECK_INTERFACE(ISoundTrigger, data, reply);
+ sound_model_handle_t handle;
+ status_t status = UNKNOWN_ERROR;
+ status_t ret = data.read(&handle, sizeof(sound_model_handle_t));
+ if (ret == NO_ERROR) {
+ sp<IMemory> eventMemory;
+ status = getModelState(handle, eventMemory);
+ if (eventMemory != NULL) {
+ ret = reply->writeStrongBinder(
+ IInterface::asBinder(eventMemory));
+ } else {
+ ret = NO_MEMORY;
+ }
+ }
+ reply->writeInt32(status);
+ return ret;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 289b7b1..bb0650f 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -188,6 +188,16 @@
return mISoundTrigger->stopRecognition(handle);
}
+status_t SoundTrigger::getModelState(sound_model_handle_t handle,
+ sp<IMemory>& eventMemory)
+{
+ Mutex::Autolock _l(mLock);
+ if (mISoundTrigger == 0) {
+ return NO_INIT;
+ }
+ return mISoundTrigger->getModelState(handle, eventMemory);
+}
+
// BpSoundTriggerClient
void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
{