Merge "Camera: Use recommended configs for shim supported parameters"
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..7c3a2f0 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,43 @@
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",
+ ],
+ version_script: "libcamera2ndk.map.txt",
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index f5ff69d..508f930 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)
@@ -39,6 +41,8 @@
LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
LOCAL_CFLAGS += -Wall -Wextra -Werror
+LOCAL_LDFLAGS += -Wl,--version-script=$(LOCAL_PATH)/libcamera2ndk.map.txt
+
LOCAL_SHARED_LIBRARIES := \
libbinder \
liblog \
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 5db4615..297d11b 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2783,7 +2783,7 @@
* {@link AIMAGE_FORMAT_RAW12 RAW12}.</li>
* <li>Processed (but not-stalling): any non-RAW format without a stall duration. Typically
* {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888},
- * <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.</li>
+ * <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>, or {@link AIMAGE_FORMAT_Y8 Y8} .</li>
* </ul>
*
* @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
@@ -3251,6 +3251,7 @@
* <li>{@link AIMAGE_FORMAT_YUV_420_888 }</li>
* <li>{@link AIMAGE_FORMAT_RAW10 }</li>
* <li>{@link AIMAGE_FORMAT_RAW12 }</li>
+ * <li>{@link AIMAGE_FORMAT_Y8 }</li>
* </ul>
* <p>All other formats may or may not have an allowed stall duration on
* a per-capability basis; refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -5558,8 +5559,8 @@
* will not slow down capture rate when applying correction. FAST may be the same as OFF if
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
- * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output.</p>
+ * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+ * not applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
@@ -7244,7 +7245,7 @@
* camera device can capture this size for at least 10 frames per second. Also the
* ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry lists at least one FPS range where
* the minimum FPS is >= 1 / minimumFrameDuration for the largest YUV_420_888 size.</p>
- * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, then those can also be
+ * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, {@link AIMAGE_FORMAT_Y8 }, then those can also be
* captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
* <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
* and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
@@ -7278,8 +7279,8 @@
* <li>The ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE entry is listed by this device.</li>
* <li>As of Android P, the ACAMERA_LENS_POSE_REFERENCE entry is listed by this device.</li>
* <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
- * normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
- * format.</li>
+ * normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the
+ * DEPTH16 format.</li>
* </ul>
* <p>Generally, depth output operates at a slower frame rate than standard color capture,
* so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
@@ -7373,6 +7374,10 @@
/**
* <p>The camera device is a monochrome camera that doesn't contain a color filter array,
* and the pixel values on U and V planes are all 128.</p>
+ * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
+ * its device level and capabilities. Additionally, if the monochrome camera device
+ * supports Y8 format, all mandatory stream combination requirements related to {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888} apply
+ * to {@link AIMAGE_FORMAT_Y8 Y8} as well.</p>
*/
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12,
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
index 8fafce2..e23502c 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
@@ -57,6 +57,7 @@
break;
case kLicenseStateReleasing:
license->set_state(License_LicenseState_RELEASING);
+ license->set_license(licenseResponse);
break;
default:
ALOGW("StoreLicense: Unknown license state: %u", state);
@@ -106,8 +107,8 @@
bool DeviceFiles::RetrieveLicense(
const std::string& keySetId, LicenseState* state, std::string* offlineLicense) {
- OfflineFile file;
+ OfflineFile file;
if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
return false;
}
@@ -128,7 +129,6 @@
}
License license = file.license();
-
switch (license.state()) {
case License_LicenseState_ACTIVE:
*state = kLicenseStateActive;
@@ -142,11 +142,14 @@
*state = kLicenseStateUnknown;
break;
}
-
*offlineLicense = license.license();
return true;
}
+bool DeviceFiles::DeleteLicense(const std::string& keySetId) {
+ return mFileHandle.RemoveFile(keySetId + kLicenseFileNameExt);
+}
+
bool DeviceFiles::DeleteAllLicenses() {
return mFileHandle.RemoveAllFiles();
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 59dfb89..55cbcf9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -70,6 +70,7 @@
mPlayPolicy.clear();
initProperties();
mSecureStops.clear();
+ mReleaseKeysMap.clear();
std::srand(std::time(nullptr));
}
@@ -155,7 +156,7 @@
// 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.
+ // signal such specific use case.
if (keyType == KeyType::OFFLINE && 0 == initData.size()) {
return Status::ERROR_DRM_CANNOT_HANDLE;
}
@@ -196,6 +197,14 @@
ALOGE("Problem releasing offline license");
return Status::ERROR_DRM_UNKNOWN;
}
+ if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
+ sp<Session> session = mSessionLibrary->createSession();
+ mReleaseKeysMap[keySetIdString] = session->sessionId();
+ } else {
+ ALOGI("key is in use, ignore release request");
+ }
+ } else {
+ ALOGE("Offline license not found, nothing to release");
}
*keyRequestType = KeyRequestType::RELEASE;
}
@@ -305,25 +314,35 @@
bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
if (isRelease) {
keySetId.assign(scopeId.begin(), scopeId.end());
+
+ auto iter = mReleaseKeysMap.find(std::string(keySetId.begin(), keySetId.end()));
+ if (iter != mReleaseKeysMap.end()) {
+ sessionId.assign(iter->second.begin(), iter->second.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();
- }
-
- setPlayPolicy();
// non offline license returns empty keySetId
keySetId.clear();
+ }
- status = session->provideKeyResponse(response);
- if (status == Status::OK) {
- if (isOfflineLicense) {
+ sp<Session> session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
+ return Void();
+ }
+ setPlayPolicy();
+
+ status = session->provideKeyResponse(response);
+ if (status == Status::OK) {
+ if (isOfflineLicense) {
+ if (isRelease) {
+ mFileHandle.DeleteLicense(keySetId);
+ } else {
if (!makeKeySetId(&keySetId)) {
_hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec<uint8_t>());
return Void();
}
+
bool ok = mFileHandle.StoreLicense(
keySetId,
DeviceFiles::kLicenseStateActive,
@@ -332,32 +351,32 @@
ALOGE("Failed to store offline license");
}
}
-
- // Test calling AMediaDrm listeners.
- sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
-
- sendExpirationUpdate(sessionId, 100);
-
- std::vector<KeyStatus> keysStatus;
- KeyStatus keyStatus;
-
- std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
- keyStatus.keyId = keyId1;
- keyStatus.type = V1_0::KeyStatusType::USABLE;
- keysStatus.push_back(keyStatus);
-
- std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
- keyStatus.keyId = keyId2;
- keyStatus.type = V1_0::KeyStatusType::EXPIRED;
- keysStatus.push_back(keyStatus);
-
- sendKeysChange(sessionId, keysStatus, true);
-
- installSecureStop(sessionId);
- } else {
- ALOGE("Failed to add key, error=%d", status);
}
- } // keyType::STREAMING || keyType::OFFLINE
+
+ // Test calling AMediaDrm listeners.
+ sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
+
+ sendExpirationUpdate(sessionId, 100);
+
+ std::vector<KeyStatus> keysStatus;
+ KeyStatus keyStatus;
+
+ std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+ keyStatus.keyId = keyId1;
+ keyStatus.type = V1_0::KeyStatusType::USABLE;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+ keyStatus.keyId = keyId2;
+ keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+ keysStatus.push_back(keyStatus);
+
+ sendKeysChange(sessionId, keysStatus, true);
+
+ installSecureStop(sessionId);
+ } else {
+ ALOGE("provideKeyResponse returns error=%d", status);
+ }
std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
_hidl_cb(status, toHidlVec(keySetIdVec));
@@ -371,10 +390,10 @@
}
DeviceFiles::LicenseState licenseState;
- std::string keySetIdString(keySetId.begin(), keySetId.end());
std::string offlineLicense;
Status status = Status::OK;
- if (!mFileHandle.RetrieveLicense(keySetIdString, &licenseState, &offlineLicense)) {
+ if (!mFileHandle.RetrieveLicense(std::string(keySetId.begin(), keySetId.end()),
+ &licenseState, &offlineLicense)) {
ALOGE("Failed to restore offline license");
return Status::ERROR_DRM_NO_LICENSE;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index dd1689f..deb5d97 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -156,7 +156,8 @@
}
if (keyType == V1_0::KeyType::STREAMING) {
request.append(kTemporarySession);
- } else if (keyType == V1_0::KeyType::OFFLINE) {
+ } else if (keyType == V1_0::KeyType::OFFLINE ||
+ keyType == V1_0::KeyType::RELEASE) {
request.append(kPersistentSession);
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
index 47f188d..43fecbb 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -3,7 +3,6 @@
// License Agreement.
#include <utils/Log.h>
-
#include <string>
#include "MemoryFileSystem.h"
@@ -54,6 +53,10 @@
size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(key);
+ }
mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
return memoryFile.getFileSize();
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
index b4319e6..d262763 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
@@ -59,7 +59,8 @@
mSessions.insert(std::pair<std::vector<uint8_t>,
sp<Session> >(sessionId, new Session(sessionId)));
- std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+ std::map<std::vector<uint8_t>, sp<Session> >::iterator itr =
+ mSessions.find(sessionId);
if (itr != mSessions.end()) {
return itr->second;
} else {
@@ -70,7 +71,8 @@
sp<Session> SessionLibrary::findSession(
const std::vector<uint8_t>& sessionId) {
Mutex::Autolock lock(mSessionsLock);
- std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+ std::map<std::vector<uint8_t>, sp<Session> >::iterator itr =
+ mSessions.find(sessionId);
if (itr != mSessions.end()) {
return itr->second;
} else {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
index a201e88..ac13d23 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
@@ -26,9 +26,9 @@
class DeviceFiles {
public:
typedef enum {
+ kLicenseStateUnknown,
kLicenseStateActive,
kLicenseStateReleasing,
- kLicenseStateUnknown,
} LicenseState;
DeviceFiles() {};
@@ -42,6 +42,8 @@
virtual bool LicenseExists(const std::string& keySetId);
+ virtual bool DeleteLicense(const std::string& keySetId);
+
virtual bool DeleteAllLicenses();
private:
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 12d8608..8e6092f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -319,6 +319,7 @@
std::vector<KeyValue> mPlayPolicy;
std::map<std::string, std::string> mStringProperties;
std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
+ std::map<std::string, std::vector<uint8_t> > mReleaseKeysMap;
std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
sp<IDrmPluginListener> mListener;
SessionLibrary *mSessionLibrary;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
index db368d7..22f8779 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
@@ -32,7 +32,9 @@
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; }
+ void setFileSize(size_t size) {
+ content.resize(size); fileSize = size;
+ }
};
MemoryFileSystem() {};
diff --git a/include/mediadrm/Crypto.h b/include/mediadrm/Crypto.h
deleted file mode 120000
index 9af6495..0000000
--- a/include/mediadrm/Crypto.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Crypto.h
\ No newline at end of file
diff --git a/include/mediadrm/Drm.h b/include/mediadrm/Drm.h
deleted file mode 120000
index ac60003..0000000
--- a/include/mediadrm/Drm.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Drm.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/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index 3eaea7c..f264501 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -117,19 +117,18 @@
Return<void> Accessor::connect(
const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
connect_cb _hidl_cb) {
- (void)observer;
sp<Connection> connection;
ConnectionId connectionId;
+ uint32_t msgId;
const StatusDescriptor* fmqDesc;
+ const InvalidationDescriptor* invDesc;
- ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
+ ResultStatus status = connect(
+ observer, false, &connection, &connectionId, &msgId, &fmqDesc, &invDesc);
if (status == ResultStatus::OK) {
- _hidl_cb(status, connection, connectionId, *fmqDesc,
- android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
- std::vector<android::hardware::GrantorDescriptor>(),
- nullptr /* nhandle */, 0 /* size */));
+ _hidl_cb(status, connection, connectionId, msgId, *fmqDesc, *invDesc);
} else {
- _hidl_cb(status, nullptr, -1LL,
+ _hidl_cb(status, nullptr, -1LL, 0,
android::hardware::MQDescriptorSync<BufferStatusMessage>(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nhandle */, 0 /* size */),
@@ -147,7 +146,15 @@
}
bool Accessor::isValid() {
- return (bool)mImpl;
+ return (bool)mImpl && mImpl->isValid();
+}
+
+ResultStatus Accessor::flush() {
+ if (mImpl) {
+ mImpl->flush();
+ return ResultStatus::OK;
+ }
+ return ResultStatus::CRITICAL_ERROR;
}
ResultStatus Accessor::allocate(
@@ -170,10 +177,15 @@
}
ResultStatus Accessor::connect(
+ const sp<IObserver> &observer, bool local,
sp<Connection> *connection, ConnectionId *pConnectionId,
- const StatusDescriptor** fmqDescPtr, bool local) {
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr) {
if (mImpl) {
- ResultStatus status = mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
+ ResultStatus status = mImpl->connect(
+ this, observer, connection, pConnectionId, pMsgId,
+ statusDescPtr, invDescPtr);
if (!local && status == ResultStatus::OK) {
sp<Accessor> accessor(this);
sConnectionDeathRecipient->add(*pConnectionId, accessor);
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index a718da1..4b5b17a 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -95,6 +95,9 @@
/** Returns whether the accessor is valid. */
bool isValid();
+ /** Invalidates all buffers which are owned by bufferpool */
+ ResultStatus flush();
+
/** Allocates a buffer from a buffer pool.
*
* @param connectionId the connection id of the client.
@@ -135,20 +138,28 @@
* created connection in order to communicate with the buffer pool. An
* FMQ for buffer status message is also created for the client.
*
- * @param connection created connection
- * @param pConnectionId the id of the created connection
- * @param fmqDescPtr FMQ descriptor for shared buffer status message
- * queue between a buffer pool and the client.
+ * @param observer client observer for buffer invalidation
* @param local true when a connection request comes from local process,
* false otherwise.
+ * @param connection created connection
+ * @param pConnectionId the id of the created connection
+ * @param pMsgId the id of the recent buffer pool message
+ * @param statusDescPtr FMQ descriptor for shared buffer status message
+ * queue between a buffer pool and the client.
+ * @param invDescPtr FMQ descriptor for buffer invalidation message
+ * queue from a buffer pool to the client.
*
* @return OK when a connection is successfully made.
* NO_MEMORY when there is no memory.
* CRITICAL_ERROR otherwise.
*/
ResultStatus connect(
+ const sp<IObserver>& observer,
+ bool local,
sp<Connection> *connection, ConnectionId *pConnectionId,
- const StatusDescriptor** fmqDescPtr, bool local);
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr);
/**
* Closes the specified connection to the client.
@@ -176,7 +187,7 @@
private:
class Impl;
- std::unique_ptr<Impl> mImpl;
+ std::shared_ptr<Impl> mImpl;
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 0ba6600..4cc8abc 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -21,6 +21,7 @@
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
+#include <thread>
#include "AccessorImpl.h"
#include "Connection.h"
@@ -47,6 +48,7 @@
const std::shared_ptr<BufferPoolAllocation> mAllocation;
const size_t mAllocSize;
const std::vector<uint8_t> mConfig;
+ bool mInvalidated;
InternalBuffer(
BufferId id,
@@ -54,11 +56,16 @@
const size_t allocSize,
const std::vector<uint8_t> &allocConfig)
: mId(id), mOwnerCount(0), mTransactionCount(0),
- mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig) {}
+ mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+ mInvalidated(false) {}
const native_handle_t *handle() {
return mAllocation->handle();
}
+
+ void invalidate() {
+ mInvalidated = true;
+ }
};
struct TransactionStatus {
@@ -138,21 +145,29 @@
}
ResultStatus Accessor::Impl::connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr) {
+ const sp<Accessor> &accessor, const sp<IObserver> &observer,
+ sp<Connection> *connection,
+ ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr) {
sp<Connection> newConnection = new Connection();
ResultStatus status = ResultStatus::CRITICAL_ERROR;
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
ConnectionId id = (int64_t)sPid << 32 | sSeqId;
- status = mBufferPool.mObserver.open(id, fmqDescPtr);
+ status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
*connection = newConnection;
*pConnectionId = id;
+ *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+ mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+ mBufferPool.mInvalidation.onConnect(id, observer);
++sSeqId;
}
+
}
mBufferPool.processStatusMessages();
mBufferPool.cleanUp();
@@ -165,6 +180,7 @@
mBufferPool.processStatusMessages();
mBufferPool.handleClose(connectionId);
mBufferPool.mObserver.close(connectionId);
+ mBufferPool.mInvalidation.onClose(connectionId);
// Since close# will be called after all works are finished, it is OK to
// evict unused buffers.
mBufferPool.cleanUp(true);
@@ -229,11 +245,30 @@
mBufferPool.cleanUp(clearCache);
}
+void Accessor::Impl::flush() {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.flush(shared_from_this());
+}
+
+void Accessor::Impl::handleInvalidateAck() {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.mInvalidation.onHandleAck();
+}
+
+bool Accessor::Impl::isValid() {
+ return mBufferPool.isValid();
+}
+
Accessor::Impl::Impl::BufferPool::BufferPool()
: mTimestampUs(getTimestampNow()),
mLastCleanUpUs(mTimestampUs),
mLastLogUs(mTimestampUs),
- mSeq(0) {}
+ mSeq(0),
+ mStartSeq(0) {
+ mValid = mInvalidationChannel.isValid();
+}
// Statistics helper
@@ -242,6 +277,8 @@
return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
}
+std::atomic<std::uint32_t> Accessor::Impl::BufferPool::Invalidation::sSeqId(0);
+
Accessor::Impl::Impl::BufferPool::~BufferPool() {
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Destruction - bufferpool %p "
@@ -255,6 +292,96 @@
percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
}
+void Accessor::Impl::BufferPool::Invalidation::onConnect(
+ ConnectionId conId, const sp<IObserver>& observer) {
+ mAcks[conId] = mInvalidationId; // starts from current invalidationId
+ mObservers.insert(std::make_pair(conId, observer));
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onClose(ConnectionId conId) {
+ mAcks.erase(conId);
+ mObservers.erase(conId);
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onAck(
+ ConnectionId conId,
+ uint32_t msgId) {
+ auto it = mAcks.find(conId);
+ if (it == mAcks.end() || isMessageLater(msgId, it->second)) {
+ mAcks[conId] = msgId;
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel) {
+ for (auto it = mPendings.begin(); it != mPendings.end();) {
+ if (it->invalidate(bufferId)) {
+ it = mPendings.erase(it);
+ uint32_t msgId = 0;
+ if (it->mNeedsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ channel.postInvalidation(msgId, it->mFrom, it->mTo);
+ sInvalidator.addAccessor(mId, it->mImpl);
+ continue;
+ }
+ ++it;
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onInvalidationRequest(
+ bool needsAck,
+ uint32_t from,
+ uint32_t to,
+ size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor::Impl> &impl) {
+ if (left == 0) {
+ uint32_t msgId = 0;
+ if (needsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ channel.postInvalidation(msgId, from, to);
+ sInvalidator.addAccessor(mId, impl);
+ } else {
+ // TODO: sending hint message?
+ Pending pending(needsAck, from, to, left, impl);
+ mPendings.push_back(pending);
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onHandleAck() {
+ if (mInvalidationId != 0) {
+ std::set<int> deads;
+ for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+ if (it->second != mInvalidationId) {
+ const sp<IObserver> observer = mObservers[it->first].promote();
+ if (observer) {
+ observer->onMessage(it->first, mInvalidationId);
+ } else {
+ deads.insert(it->first);
+ }
+ }
+ }
+ if (deads.size() > 0) {
+ for (auto it = deads.begin(); it != deads.end(); ++it) {
+ onClose(*it);
+ }
+ }
+ }
+ // All invalidation Ids are synced.
+ sInvalidator.delAccessor(mId);
+}
+
bool Accessor::Impl::BufferPool::handleOwnBuffer(
ConnectionId connectionId, BufferId bufferId) {
@@ -275,8 +402,15 @@
iter->second->mOwnerCount--;
if (iter->second->mOwnerCount == 0 &&
iter->second->mTransactionCount == 0) {
- mStats.onBufferUnused(iter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!iter->second->mInvalidated) {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mStats.onBufferEvicted(iter->second->mAllocSize);
+ mBuffers.erase(iter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
}
erase(&mUsingConnections, bufferId, connectionId);
@@ -352,8 +486,15 @@
bufferIter->second->mTransactionCount--;
if (bufferIter->second->mOwnerCount == 0
&& bufferIter->second->mTransactionCount == 0) {
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(message.bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(message.bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+ }
}
mTransactions.erase(found);
}
@@ -400,7 +541,7 @@
ret = handleTransferResult(message);
break;
case BufferStatus::INVALIDATION_ACK:
- // TODO
+ mInvalidation.onAck(message.connectionId, message.bufferId);
break;
}
if (ret == false) {
@@ -423,8 +564,15 @@
if (bufferIter->second->mOwnerCount == 0 &&
bufferIter->second->mTransactionCount == 0) {
// TODO: handle freebuffer insert fail
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
}
}
@@ -446,8 +594,15 @@
if (bufferIter->second->mOwnerCount == 0 &&
bufferIter->second->mTransactionCount == 0) {
// TODO: handle freebuffer insert fail
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
mTransactions.erase(iter);
}
@@ -538,6 +693,121 @@
}
}
+void Accessor::Impl::BufferPool::invalidate(
+ bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor::Impl> &impl) {
+ for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+ if (isBufferInRange(from, to, *freeIt)) {
+ auto it = mBuffers.find(*freeIt);
+ if (it != mBuffers.end() &&
+ it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+ mStats.onBufferEvicted(it->second->mAllocSize);
+ mBuffers.erase(it);
+ freeIt = mFreeBuffers.erase(freeIt);
+ continue;
+ } else {
+ ALOGW("bufferpool inconsistent!");
+ }
+ }
+ ++freeIt;
+ }
+
+ size_t left = 0;
+ for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+ if (isBufferInRange(from, to, it->first)) {
+ it->second->invalidate();
+ ++left;
+ }
+ }
+ mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void Accessor::Impl::BufferPool::flush(const std::shared_ptr<Accessor::Impl> &impl) {
+ BufferId from = mStartSeq;
+ BufferId to = mSeq;
+ mStartSeq = mSeq;
+ // TODO: needsAck params
+ if (from != to) {
+ invalidate(true, from, to, impl);
+ }
+}
+
+void Accessor::Impl::invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready) {
+ while(true) {
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ if (!ready) {
+ cv.wait(lock);
+ }
+ copied.insert(accessors.begin(), accessors.end());
+ }
+ std::list<ConnectionId> erased;
+ for (auto it = copied.begin(); it != copied.end(); ++it) {
+ const std::shared_ptr<Accessor::Impl> impl = it->second.lock();
+ if (!impl) {
+ erased.push_back(it->first);
+ } else {
+ impl->handleInvalidateAck();
+ }
+ }
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ for (auto it = erased.begin(); it != erased.end(); ++it) {
+ accessors.erase(*it);
+ }
+ if (accessors.size() == 0) {
+ ready = false;
+ } else {
+ // prevent draining cpu.
+ lock.unlock();
+ std::this_thread::yield();
+ }
+ }
+ }
+}
+
+Accessor::Impl::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+ std::thread invalidator(
+ invalidatorThread,
+ std::ref(mAccessors),
+ std::ref(mMutex),
+ std::ref(mCv),
+ std::ref(mReady));
+ invalidator.detach();
+}
+
+void Accessor::Impl::AccessorInvalidator::addAccessor(
+ uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl) {
+ bool notify = false;
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mAccessors.find(accessorId) == mAccessors.end()) {
+ if (!mReady) {
+ mReady = true;
+ notify = true;
+ }
+ mAccessors.insert(std::make_pair(accessorId, impl));
+ }
+ lock.unlock();
+ if (notify) {
+ mCv.notify_one();
+ }
+}
+
+void Accessor::Impl::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mAccessors.erase(accessorId);
+ if (mAccessors.size() == 0) {
+ mReady = false;
+ }
+}
+
+Accessor::Impl::AccessorInvalidator Accessor::Impl::sInvalidator;
+
} // namespace implementation
} // namespace V2_0
} // namespace bufferpool
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 1d33880..6b03494 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -19,6 +19,7 @@
#include <map>
#include <set>
+#include <condition_variable>
#include "Accessor.h"
namespace android {
@@ -33,15 +34,20 @@
/**
* An implementation of a buffer pool accessor(or a buffer pool implementation.) */
-class Accessor::Impl {
+class Accessor::Impl
+ : public std::enable_shared_from_this<Accessor::Impl> {
public:
Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
~Impl();
ResultStatus connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr);
+ const sp<Accessor> &accessor, const sp<IObserver> &observer,
+ sp<Connection> *connection,
+ ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr);
ResultStatus close(ConnectionId connectionId);
@@ -55,8 +61,14 @@
BufferId bufferId,
const native_handle_t** handle);
+ void flush();
+
void cleanUp(bool clearCache);
+ bool isValid();
+
+ void handleInvalidateAck();
+
private:
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
@@ -78,7 +90,10 @@
int64_t mLastCleanUpUs;
int64_t mLastLogUs;
BufferId mSeq;
+ BufferId mStartSeq;
+ bool mValid;
BufferStatusObserver mObserver;
+ BufferInvalidationChannel mInvalidationChannel;
std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
@@ -95,6 +110,54 @@
std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
std::set<BufferId> mFreeBuffers;
+ struct Invalidation {
+ static std::atomic<std::uint32_t> sSeqId;
+
+ struct Pending {
+ bool mNeedsAck;
+ uint32_t mFrom;
+ uint32_t mTo;
+ size_t mLeft;
+ const std::weak_ptr<Accessor::Impl> mImpl;
+ Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+ const std::shared_ptr<Accessor::Impl> &impl)
+ : mNeedsAck(needsAck),
+ mFrom(from),
+ mTo(to),
+ mLeft(left),
+ mImpl(impl)
+ {}
+
+ bool invalidate(uint32_t bufferId) {
+ return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+ }
+ };
+
+ std::list<Pending> mPendings;
+ std::map<ConnectionId, uint32_t> mAcks;
+ std::map<ConnectionId, const wp<IObserver>> mObservers;
+ uint32_t mInvalidationId;
+ uint32_t mId;
+
+ Invalidation() : mInvalidationId(0), mId(sSeqId.fetch_add(1)) {}
+
+ void onConnect(ConnectionId conId, const sp<IObserver> &observer);
+
+ void onClose(ConnectionId conId);
+
+ void onAck(ConnectionId conId, uint32_t msgId);
+
+ void onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel);
+
+ void onInvalidationRequest(
+ bool needsAck, uint32_t from, uint32_t to, size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor::Impl> &impl);
+
+ void onHandleAck();
+ } mInvalidation;
/// Buffer pool statistics which tracks allocation and transfer statistics.
struct Stats {
/// Total size of allocations which are used or available to use.
@@ -164,6 +227,13 @@
}
} mStats;
+ bool isValid() {
+ return mValid;
+ }
+
+ void invalidate(bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor::Impl> &impl);
+
public:
/** Creates a buffer pool. */
BufferPool();
@@ -286,8 +356,33 @@
*/
void cleanUp(bool clearCache = false);
+ /**
+ * Processes pending buffer status messages and invalidate all current
+ * free buffers. Active buffers are invalidated after being inactive.
+ */
+ void flush(const std::shared_ptr<Accessor::Impl> &impl);
+
friend class Accessor::Impl;
} mBufferPool;
+
+ struct AccessorInvalidator {
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mReady;
+
+ AccessorInvalidator();
+ void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
+ void delAccessor(uint32_t accessorId);
+ };
+
+ static AccessorInvalidator sInvalidator;
+
+ static void invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready);
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 413125a..cd4e06e 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -8,6 +8,7 @@
"BufferStatus.cpp",
"ClientManager.cpp",
"Connection.cpp",
+ "Observer.cpp",
],
export_include_dirs: [
"include",
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 0f763f7..c80beff 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -36,9 +36,9 @@
class BufferPoolClient::Impl
: public std::enable_shared_from_this<BufferPoolClient::Impl> {
public:
- explicit Impl(const sp<Accessor> &accessor);
+ explicit Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer);
- explicit Impl(const sp<IAccessor> &accessor);
+ explicit Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer);
bool isValid() {
return mValid;
@@ -58,6 +58,10 @@
bool isActive(int64_t *lastTransactionUs, bool clearCache);
+ void receiveInvalidation(uint32_t msgID);
+
+ ResultStatus flush();
+
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
std::shared_ptr<BufferPoolData> *buffer);
@@ -83,10 +87,14 @@
void trySyncFromRemote();
- bool syncReleased();
+ bool syncReleased(uint32_t msgId = 0);
void evictCaches(bool clearCache = false);
+ void invalidateBuffer(BufferId id);
+
+ void invalidateRange(BufferId from, BufferId to);
+
ResultStatus allocateBufferHandle(
const std::vector<uint8_t>& params, BufferId *bufferId,
native_handle_t **handle);
@@ -106,6 +114,7 @@
uint32_t mSeqId;
ConnectionId mConnectionId;
int64_t mLastEvictCacheUs;
+ std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
// CachedBuffers
struct BufferCache {
@@ -130,12 +139,16 @@
} mCache;
// FMQ - release notifier
- struct {
+ struct ReleaseCache {
std::mutex mLock;
// TODO: use only one list?(using one list may dealy sending messages?)
std::list<BufferId> mReleasingIds;
std::list<BufferId> mReleasedIds;
+ uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+ bool mInvalidateAck;
std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+ ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
} mReleasing;
// This lock is held during synchronization from remote side.
@@ -162,7 +175,6 @@
struct BufferPoolClient::Impl::ClientBuffer {
private:
- bool mInvalidated; // TODO: implement
int64_t mExpireUs;
bool mHasCache;
ConnectionId mConnectionId;
@@ -177,9 +189,8 @@
public:
ClientBuffer(
ConnectionId connectionId, BufferId id, native_handle_t *handle)
- : mInvalidated(false), mHasCache(false),
- mConnectionId(connectionId), mId(id), mHandle(handle) {
- (void)mInvalidated;
+ : mHasCache(false), mConnectionId(connectionId),
+ mId(id), mHandle(handle) {
mExpireUs = getTimestampNow() + kCacheTtlUs;
}
@@ -190,6 +201,10 @@
}
}
+ BufferId id() const {
+ return mId;
+ }
+
bool expire() const {
int64_t now = getTimestampNow();
return now >= mExpireUs;
@@ -244,41 +259,53 @@
}
};
-BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer)
: mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
mLastEvictCacheUs(getTimestampNow()) {
- const StatusDescriptor *fmqDesc;
+ const StatusDescriptor *statusDesc;
+ const InvalidationDescriptor *invDesc;
ResultStatus status = accessor->connect(
- &mLocalConnection, &mConnectionId, &fmqDesc, true);
+ observer, true,
+ &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+ &statusDesc, &invDesc);
if (status == ResultStatus::OK) {
mReleasing.mStatusChannel =
- std::make_unique<BufferStatusChannel>(*fmqDesc);
+ std::make_unique<BufferStatusChannel>(*statusDesc);
+ mInvalidationListener =
+ std::make_unique<BufferInvalidationListener>(*invDesc);
mValid = mReleasing.mStatusChannel &&
- mReleasing.mStatusChannel->isValid();
+ mReleasing.mStatusChannel->isValid() &&
+ mInvalidationListener &&
+ mInvalidationListener->isValid();
}
}
-BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer)
: mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
mLastEvictCacheUs(getTimestampNow()) {
bool valid = false;
- sp<IObserver> observer; // TODO
sp<IConnection>& outConnection = mRemoteConnection;
ConnectionId& id = mConnectionId;
+ uint32_t& outMsgId = mReleasing.mInvalidateId;
std::unique_ptr<BufferStatusChannel>& outChannel =
mReleasing.mStatusChannel;
+ std::unique_ptr<BufferInvalidationListener>& outObserver =
+ mInvalidationListener;
Return<void> transResult = accessor->connect(
observer,
- [&valid, &outConnection, &id, &outChannel]
+ [&valid, &outConnection, &id, &outMsgId, &outChannel, &outObserver]
(ResultStatus status, sp<IConnection> connection,
- ConnectionId connectionId, const StatusDescriptor& desc,
+ ConnectionId connectionId, uint32_t msgId,
+ const StatusDescriptor& statusDesc,
const InvalidationDescriptor& invDesc) {
- (void) invDesc;
if (status == ResultStatus::OK) {
outConnection = connection;
id = connectionId;
- outChannel = std::make_unique<BufferStatusChannel>(desc);
- if (outChannel && outChannel->isValid()) {
+ outMsgId = msgId;
+ outChannel = std::make_unique<BufferStatusChannel>(statusDesc);
+ outObserver = std::make_unique<BufferInvalidationListener>(invDesc);
+ if (outChannel && outChannel->isValid() &&
+ outObserver && outObserver->isValid()) {
valid = true;
}
}
@@ -302,6 +329,24 @@
return active;
}
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased(messageId);
+ // TODO: evict cache required?
+}
+
+ResultStatus BufferPoolClient::Impl::flush() {
+ if (!mLocal || !mLocalConnection || !mValid) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ {
+ std::unique_lock<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches();
+ return mLocalConnection->flush();
+ }
+}
+
ResultStatus BufferPoolClient::Impl::allocate(
const std::vector<uint8_t> ¶ms,
native_handle_t **pHandle,
@@ -455,6 +500,11 @@
bool BufferPoolClient::Impl::postSend(
BufferId bufferId, ConnectionId receiver,
TransactionId *transactionId, int64_t *timestampUs) {
+ {
+ // TODO: don't need to call syncReleased every time
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ }
bool ret = false;
bool needsSync = false;
{
@@ -538,34 +588,74 @@
}
// should have mCache.mLock
-bool BufferPoolClient::Impl::syncReleased() {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- if (mReleasing.mReleasingIds.size() > 0) {
- mReleasing.mStatusChannel->postBufferRelease(
- mConnectionId, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
- }
- if (mReleasing.mReleasedIds.size() > 0) {
- for (BufferId& id: mReleasing.mReleasedIds) {
- ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
- auto found = mCache.mBuffers.find(id);
- if (found != mCache.mBuffers.end()) {
- if (found->second->onCacheRelease()) {
- mCache.decActive_l();
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+ bool cleared = false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (mReleasing.mReleasingIds.size() > 0) {
+ mReleasing.mStatusChannel->postBufferRelease(
+ mConnectionId, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ }
+ if (mReleasing.mReleasedIds.size() > 0) {
+ for (BufferId& id: mReleasing.mReleasedIds) {
+ ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+ auto found = mCache.mBuffers.find(id);
+ if (found != mCache.mBuffers.end()) {
+ if (found->second->onCacheRelease()) {
+ mCache.decActive_l();
+ } else {
+ // should not happen!
+ ALOGW("client %lld cache release status inconsitent!",
+ (long long)mConnectionId);
+ }
} else {
// should not happen!
- ALOGW("client %lld cache release status inconsitent!",
- (long long)mConnectionId);
+ ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
}
+ }
+ mReleasing.mReleasedIds.clear();
+ cleared = true;
+ }
+ }
+ std::vector<BufferInvalidationMessage> invalidations;
+ mInvalidationListener->getInvalidations(invalidations);
+ uint32_t lastMsgId = 0;
+ if (invalidations.size() > 0) {
+ for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+ if (it->messageId != 0) {
+ lastMsgId = it->messageId;
+ }
+ if (it->fromBufferId == it->toBufferId) {
+ // TODO: handle fromBufferId = UINT32_MAX
+ invalidateBuffer(it->fromBufferId);
} else {
- // should not happen!
- ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
+ invalidateRange(it->fromBufferId, it->toBufferId);
}
}
- mReleasing.mReleasedIds.clear();
- return true;
}
- return false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (lastMsgId != 0) {
+ if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = lastMsgId;
+ mReleasing.mInvalidateAck = false;
+ }
+ } else if (messageId != 0) {
+ // messages are drained.
+ if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = lastMsgId;
+ mReleasing.mInvalidateAck = true;
+ }
+ }
+ if (!mReleasing.mInvalidateAck) {
+ // post ACK
+ mReleasing.mStatusChannel->postBufferInvalidateAck(
+ mConnectionId,
+ mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+ }
+ }
+ return cleared;
}
// should have mCache.mLock
@@ -587,6 +677,49 @@
}
}
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+ if (id == it->second->id()) {
+ if (!it->second->hasCache()) {
+ mCache.mBuffers.erase(it);
+ ALOGV("cache invalidated %lld : buffer %u",
+ (long long)mConnectionId, id);
+ } else {
+ ALOGW("Inconsitent invalidation %lld : activer buffer!! %u",
+ (long long)mConnectionId, (unsigned int)id);
+ }
+ break;
+ }
+ }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+ size_t invalidated = 0;
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+ if (!it->second->hasCache()) {
+ BufferId bid = it->second->id();
+ if (from < to) {
+ if (from <= bid && bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ } else {
+ if (from <= bid || bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ }
+ }
+ ++it;
+ }
+ ALOGV("cache invalidated %lld : # of invalidated %zu",
+ (long long)mConnectionId, invalidated);
+}
+
ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
const std::vector<uint8_t>& params, BufferId *bufferId,
native_handle_t** handle) {
@@ -629,12 +762,14 @@
}
-BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor,
+ const sp<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
}
-BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor,
+ const sp<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
}
BufferPoolClient::~BufferPoolClient() {
@@ -672,6 +807,19 @@
return ResultStatus::CRITICAL_ERROR;
}
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+ if (isValid()) {
+ mImpl->receiveInvalidation(msgId);
+ }
+}
+
+ResultStatus BufferPoolClient::flush() {
+ if (isValid()) {
+ return mImpl->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus BufferPoolClient::allocate(
const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
index 1889ea3..e8d9ae6 100644
--- a/media/bufferpool/2.0/BufferPoolClient.h
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -49,7 +49,8 @@
* Creates a buffer pool client from a local buffer pool
* (via ClientManager#create).
*/
- explicit BufferPoolClient(const sp<Accessor> &accessor);
+ explicit BufferPoolClient(const sp<Accessor> &accessor,
+ const sp<IObserver> &observer);
/**
* Creates a buffer pool client from a remote buffer pool
@@ -57,7 +58,8 @@
* Note: A buffer pool client created with remote buffer pool cannot
* allocate a buffer.
*/
- explicit BufferPoolClient(const sp<IAccessor> &accessor);
+ explicit BufferPoolClient(const sp<IAccessor> &accessor,
+ const sp<IObserver> &observer);
/** Destructs a buffer pool client. */
~BufferPoolClient();
@@ -73,6 +75,10 @@
ResultStatus getAccessor(sp<IAccessor> *accessor);
+ void receiveInvalidation(uint32_t msgId);
+
+ ResultStatus flush();
+
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
std::shared_ptr<BufferPoolData> *buffer);
@@ -92,6 +98,7 @@
std::shared_ptr<Impl> mImpl;
friend struct ClientManager;
+ friend struct Observer;
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/BufferStatus.cpp b/media/bufferpool/2.0/BufferStatus.cpp
index 0d3f5a3..6937260 100644
--- a/media/bufferpool/2.0/BufferStatus.cpp
+++ b/media/bufferpool/2.0/BufferStatus.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BufferPoolStatus"
//#define LOG_NDEBUG 0
+#include <thread>
#include <time.h>
#include "BufferStatus.h"
@@ -37,6 +38,18 @@
return stamp;
}
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+ return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+ if (from < to) {
+ return from <= bufferId && bufferId < to;
+ } else { // wrap happens
+ return from <= bufferId || bufferId < to;
+ }
+}
+
static constexpr int kNumElementsInQueue = 1024*16;
static constexpr int kMinElementsToSyncInQueue = 128;
@@ -139,6 +152,29 @@
}
}
+void BufferStatusChannel::postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool *invalidated) {
+ if (mValid && !*invalidated) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ if (avail > 0) {
+ BufferStatusMessage message;
+ message.newStatus = BufferStatus::INVALIDATION_ACK;
+ message.bufferId = invalidateId;
+ message.connectionId = connectionId;
+ if (!mBufferStatusQueue->write(&message, 1)) {
+ // Since avaliable # of writes are already confirmed,
+ // this should not happen.
+ // TODO: error handing?
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return;
+ }
+ *invalidated = true;
+ }
+ }
+}
+
bool BufferStatusChannel::postBufferStatusMessage(
TransactionId transactionId, BufferId bufferId,
BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
@@ -182,6 +218,83 @@
return false;
}
+BufferInvalidationListener::BufferInvalidationListener(
+ const InvalidationDescriptor &fmqDesc) {
+ std::unique_ptr<BufferInvalidationQueue> queue =
+ std::make_unique<BufferInvalidationQueue>(fmqDesc);
+ if (!queue || queue->isValid() == false) {
+ mValid = false;
+ return;
+ }
+ mValid = true;
+ mBufferInvalidationQueue = std::move(queue);
+ // drain previous messages
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (avail > 0) {
+ mBufferInvalidationQueue->read(temp.data(), avail);
+ }
+}
+
+void BufferInvalidationListener::getInvalidations(
+ std::vector<BufferInvalidationMessage> &messages) {
+ // Try twice in case of overflow.
+ // TODO: handling overflow though it may not happen.
+ for (int i = 0; i < 2; ++i) {
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ if (avail > 0) {
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+ messages.reserve(messages.size() + avail);
+ for (auto it = temp.begin(); it != temp.end(); ++it) {
+ messages.push_back(*it);
+ }
+ break;
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+bool BufferInvalidationListener::isValid() {
+ return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+ : mValid(true),
+ mBufferInvalidationQueue(
+ std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+ if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+ mValid = false;
+ }
+}
+
+bool BufferInvalidationChannel::isValid() {
+ return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(const InvalidationDescriptor **fmqDescPtr) {
+ if (mValid) {
+ *fmqDescPtr = mBufferInvalidationQueue->getDesc();
+ } else {
+ *fmqDescPtr = nullptr;
+ }
+}
+
+void BufferInvalidationChannel::postInvalidation(
+ uint32_t msgId, BufferId fromId, BufferId toId) {
+ BufferInvalidationMessage message;
+
+ message.messageId = msgId;
+ message.fromBufferId = fromId;
+ message.toBufferId = toId;
+ // TODO: handle failure (it does not happen normally.)
+ mBufferInvalidationQueue->write(&message);
+}
+
} // namespace implementation
} // namespace V2_0
} // namespace bufferpool
diff --git a/media/bufferpool/2.0/BufferStatus.h b/media/bufferpool/2.0/BufferStatus.h
index 777a320..fa65838 100644
--- a/media/bufferpool/2.0/BufferStatus.h
+++ b/media/bufferpool/2.0/BufferStatus.h
@@ -37,9 +37,13 @@
/** Returns monotonic timestamp in Us since fixed point in time. */
int64_t getTimestampNow();
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
/**
- * A collection of FMQ for a buffer pool. buffer ownership/status change
- * messages are sent via the FMQs from the clients.
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
*/
class BufferStatusObserver {
private:
@@ -47,7 +51,8 @@
mBufferStatusQueues;
public:
- /** Creates an FMQ for the specified connection(client).
+ /** Creates a buffer status message FMQ for the specified
+ * connection(client).
*
* @param connectionId connection Id of the specified client.
* @param fmqDescPtr double ptr of created FMQ's descriptor.
@@ -58,7 +63,8 @@
*/
ResultStatus open(ConnectionId id, const StatusDescriptor** fmqDescPtr);
- /** Closes an FMQ for the specified connection(client).
+ /** Closes a buffer status message FMQ for the specified
+ * connection(client).
*
* @param connectionId connection Id of the specified client.
*
@@ -75,8 +81,8 @@
};
/**
- * An FMQ for a buffer pool client. Buffer ownership/status change messages
- * are sent via the fmq to the buffer pool.
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
*/
class BufferStatusChannel {
private:
@@ -85,7 +91,8 @@
public:
/**
- * Connects to an FMQ from a descriptor of the created FMQ.
+ * Connects to a buffer status message FMQ from a descriptor of
+ * the created FMQ.
*
* @param fmqDesc Descriptor of the created FMQ.
*/
@@ -131,6 +138,86 @@
ConnectionId connectionId,
ConnectionId targetId,
std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+ /**
+ * Posts a buffer invaliadation messge to the buffer pool.
+ *
+ * @param connectionId connection Id of the client.
+ * @param invalidateId invalidation ack to the buffer pool.
+ * if invalidation id is zero, the ack will not be
+ * posted.
+ * @param invalidated sets {@code true} only when the invalidation ack is
+ * posted.
+ */
+ void postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool *invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+ *
+ * @param fmqDesc Descriptor of the created FMQ.
+ */
+ BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+ /** Retrieves all pending buffer invalidation messages from the buffer pool.
+ *
+ * @param messages retrieved pending messages.
+ */
+ void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+ /** Returns whether the FMQ is connected succesfully. */
+ bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Creates a buffer invalidation FMQ for a buffer pool.
+ */
+ BufferInvalidationChannel();
+
+ /** Returns whether the FMQ is connected succesfully. */
+ bool isValid();
+
+ /**
+ * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+ * be passed to the client for buffer invalidation handling.
+ *
+ * @param fmqDescPtr double ptr of created FMQ's descriptor.
+ */
+ void getDesc(const InvalidationDescriptor **fmqDescPtr);
+
+ /** Posts a buffer invalidation for invalidated buffers.
+ *
+ * @param msgId Invalidation message id which is used when clients send
+ * acks back via BufferStatusMessage
+ * @param fromId The start bufferid of the invalidated buffers(inclusive)
+ * @param toId The end bufferId of the invalidated buffers(inclusive)
+ */
+ void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index eeaf093..f8531d8 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <utils/Log.h>
#include "BufferPoolClient.h"
+#include "Observer.h"
namespace android {
namespace hardware {
@@ -106,6 +107,8 @@
ResultStatus close(ConnectionId connectionId);
+ ResultStatus flush(ConnectionId connectionId);
+
ResultStatus allocate(ConnectionId connectionId,
const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
@@ -153,10 +156,13 @@
mClients;
} mActive;
+ sp<Observer> mObserver;
+
ClientManagerCookieHolder mRemoteClientCookies;
};
-ClientManager::Impl::Impl() {}
+ClientManager::Impl::Impl()
+ : mObserver(new Observer()) {}
ResultStatus ClientManager::Impl::registerSender(
const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
@@ -185,7 +191,7 @@
lock.unlock();
ResultStatus result = ResultStatus::OK;
const std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
lock.lock();
if (!client) {
result = ResultStatus::NO_MEMORY;
@@ -197,6 +203,7 @@
const std::weak_ptr<BufferPoolClient> wclient = client;
mCache.mClients.push_back(std::make_pair(accessor, wclient));
ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
{
std::lock_guard<std::mutex> lock(mActive.mMutex);
mActive.mClients.insert(std::make_pair(conId, client));
@@ -266,8 +273,9 @@
if (!accessor || !accessor->isValid()) {
return ResultStatus::CRITICAL_ERROR;
}
+ // TODO: observer is local. use direct call instead of hidl call.
std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
if (!client || !client->isValid()) {
return ResultStatus::CRITICAL_ERROR;
}
@@ -280,6 +288,7 @@
const std::weak_ptr<BufferPoolClient> wclient = client;
mCache.mClients.push_back(std::make_pair(accessor, wclient));
ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
{
std::lock_guard<std::mutex> lock(mActive.mMutex);
mActive.mClients.insert(std::make_pair(conId, client));
@@ -291,12 +300,13 @@
}
ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
- std::lock_guard<std::mutex> lock1(mCache.mMutex);
- std::lock_guard<std::mutex> lock2(mActive.mMutex);
+ std::unique_lock<std::mutex> lock1(mCache.mMutex);
+ std::unique_lock<std::mutex> lock2(mActive.mMutex);
auto it = mActive.mClients.find(connectionId);
if (it != mActive.mClients.end()) {
sp<IAccessor> accessor;
it->second->getAccessor(&accessor);
+ std::shared_ptr<BufferPoolClient> closing = it->second;
mActive.mClients.erase(connectionId);
for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
// clean up dead client caches
@@ -307,11 +317,27 @@
cit++;
}
}
+ lock2.unlock();
+ lock1.unlock();
+ closing->flush();
return ResultStatus::OK;
}
return ResultStatus::NOT_FOUND;
}
+ResultStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+ return client->flush();
+}
+
ResultStatus ClientManager::Impl::allocate(
ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
@@ -461,6 +487,13 @@
return ResultStatus::CRITICAL_ERROR;
}
+ResultStatus ClientManager::flush(ConnectionId connectionId) {
+ if (mImpl) {
+ return mImpl->flush(connectionId);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus ClientManager::allocate(
ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
diff --git a/media/bufferpool/2.0/Connection.cpp b/media/bufferpool/2.0/Connection.cpp
index cd837a1..6bd0e79 100644
--- a/media/bufferpool/2.0/Connection.cpp
+++ b/media/bufferpool/2.0/Connection.cpp
@@ -60,6 +60,13 @@
}
}
+ResultStatus Connection::flush() {
+ if (mInitialized && mAccessor) {
+ return mAccessor->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus Connection::allocate(
const std::vector<uint8_t> ¶ms, BufferId *bufferId,
const native_handle_t **handle) {
diff --git a/media/bufferpool/2.0/Connection.h b/media/bufferpool/2.0/Connection.h
index e2b47f1..8507749 100644
--- a/media/bufferpool/2.0/Connection.h
+++ b/media/bufferpool/2.0/Connection.h
@@ -44,6 +44,11 @@
Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
/**
+ * Invalidates all buffers which are active and/or are ready to be recycled.
+ */
+ ResultStatus flush();
+
+ /**
* Allocates a buffer using the specified parameters. Recycles a buffer if
* it is possible. The returned buffer can be transferred to other remote
* clients(Connection).
diff --git a/media/bufferpool/2.0/Observer.cpp b/media/bufferpool/2.0/Observer.cpp
new file mode 100644
index 0000000..5b23160
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Observer.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+Return<void> Observer::onMessage(int64_t connectionId, uint32_t msgId) {
+ std::unique_lock<std::mutex> lock(mLock);
+ auto it = mClients.find(connectionId);
+ if (it != mClients.end()) {
+ const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+ if (!client) {
+ mClients.erase(it);
+ } else {
+ lock.unlock();
+ client->receiveInvalidation(msgId);
+ }
+ }
+ return Void();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient) {
+ std::lock_guard<std::mutex> lock(mLock);
+ for (auto it = mClients.begin(); it != mClients.end();) {
+ if (!it->second.lock() || it->first == connectionId) {
+ it = mClients.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mClients.erase(connectionId);
+}
+
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace bufferpool
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/bufferpool/2.0/Observer.h b/media/bufferpool/2.0/Observer.h
new file mode 100644
index 0000000..42bd7c1
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "BufferPoolClient.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Observer : public IObserver {
+ // Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+ Return<void> onMessage(int64_t connectionId, uint32_t msgId) override;
+
+ ~Observer();
+
+ void addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient);
+
+ void delClient(ConnectionId connectionId);
+
+private:
+ Observer();
+
+ friend struct ClientManager;
+
+ std::mutex mLock;
+ std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace bufferpool
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
index cfc3bc3..953c304 100644
--- a/media/bufferpool/2.0/include/bufferpool/ClientManager.h
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -92,6 +92,18 @@
ResultStatus close(ConnectionId connectionId);
/**
+ * Evicts cached allocations. If it's local connection, release the
+ * previous allocations and do not recycle current active allocations.
+ *
+ * @param connectionId The id of the connection.
+ *
+ * @return OK when the connection is resetted.
+ * NOT_FOUND when the specified connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ ResultStatus flush(ConnectionId connectionId);
+
+ /**
* Allocates a buffer from the specified connection.
*
* @param connectionId The id of the connection.
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index fcfdaff..be6d9fd 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -622,6 +622,8 @@
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
AMediaFormat_setInt32(mTrackMetadata,
+ AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, getBitsPerSample());
+ AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
// sample rate is non-zero, so division by zero not possible
AMediaFormat_setInt64(mTrackMetadata,
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 681fd35..ae108ec 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -12,6 +12,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index e15cbdb..1fdac05 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -127,15 +127,15 @@
BlockIterator &operator=(const BlockIterator &);
};
-struct MatroskaSource : public MediaTrackHelper {
+struct MatroskaSource : public MediaTrackHelperV2 {
MatroskaSource(MatroskaExtractor *extractor, size_t index);
- 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);
protected:
@@ -161,7 +161,7 @@
status_t advance();
status_t setWebmBlockCryptoInfo(MediaBufferBase *mbuf);
- status_t readBlock();
+ media_status_t readBlock();
void clearPendingFrames();
MatroskaSource(const MatroskaSource &);
@@ -226,43 +226,30 @@
index),
mNALSizeLen(-1) {
MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
- MetaDataBase &meta = trackInfo.mMeta;
+ AMediaFormat *meta = trackInfo.mMeta;
const char *mime;
- CHECK(meta.findCString(kKeyMIMEType, &mime));
+ CHECK(AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mime));
mIsAudio = !strncasecmp("audio/", mime, 6);
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
mType = AVC;
- uint32_t dummy;
- const uint8_t *avcc;
- size_t avccSize;
int32_t nalSizeLen = trackInfo.mNalLengthSize;
- if (nalSizeLen >= 0) {
- if (nalSizeLen <= 4) {
- mNALSizeLen = nalSizeLen;
- }
- } else if (meta.findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
- && avccSize >= 5u) {
- mNALSizeLen = 1 + (avcc[4] & 3);
- ALOGV("mNALSizeLen = %zd", mNALSizeLen);
+ if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+ mNALSizeLen = nalSizeLen;
} else {
- ALOGE("No mNALSizeLen");
+ ALOGE("No AVC mNALSizeLen");
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
mType = HEVC;
- uint32_t dummy;
- const uint8_t *hvcc;
- size_t hvccSize;
- if (meta.findData(kKeyHVCC, &dummy, (const void **)&hvcc, &hvccSize)
- && hvccSize >= 22u) {
- mNALSizeLen = 1 + (hvcc[14+7] & 3);
- ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+ int32_t nalSizeLen = trackInfo.mNalLengthSize;
+ if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+ mNALSizeLen = nalSizeLen;
} else {
- ALOGE("No mNALSizeLen");
+ ALOGE("No HEVC mNALSizeLen");
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
@@ -273,25 +260,24 @@
clearPendingFrames();
}
-status_t MatroskaSource::start() {
+media_status_t MatroskaSource::start() {
if (mType == AVC && mNALSizeLen < 0) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
mBlockIter.reset();
- return OK;
+ return AMEDIA_OK;
}
-status_t MatroskaSource::stop() {
+media_status_t MatroskaSource::stop() {
clearPendingFrames();
- return OK;
+ return AMEDIA_OK;
}
-status_t MatroskaSource::getFormat(MetaDataBase &meta) {
- meta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
- return OK;
+media_status_t MatroskaSource::getFormat(AMediaFormat *meta) {
+ return AMediaFormat_copy(meta, mExtractor->mTracks.itemAt(mTrackIndex).mMeta);
}
////////////////////////////////////////////////////////////////////////////////
@@ -608,11 +594,11 @@
MetaDataBase &meta = mbuf->meta_data();
if (encrypted) {
uint8_t ctrCounter[16] = { 0 };
- uint32_t type;
const uint8_t *keyId;
size_t keyIdSize;
- const MetaDataBase &trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
- CHECK(trackMeta.findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize));
+ AMediaFormat *trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+ AMediaFormat_getBuffer(trackMeta, AMEDIAFORMAT_KEY_CRYPTO_KEY,
+ (void**)&keyId, &keyIdSize);
meta.setData(kKeyCryptoKey, 0, keyId, keyIdSize);
memcpy(ctrCounter, data + 1, 8);
meta.setData(kKeyCryptoIV, 0, ctrCounter, 16);
@@ -715,11 +701,11 @@
return OK;
}
-status_t MatroskaSource::readBlock() {
+media_status_t MatroskaSource::readBlock() {
CHECK(mPendingFrames.empty());
if (mBlockIter.eos()) {
- return ERROR_END_OF_STREAM;
+ return AMEDIA_ERROR_END_OF_STREAM;
}
const mkvparser::Block *block = mBlockIter.block();
@@ -731,7 +717,7 @@
const mkvparser::Block::Frame &frame = block->GetFrame(i);
size_t len = frame.len;
if (SIZE_MAX - len < trackInfo->mHeaderLen) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
len += trackInfo->mHeaderLen;
@@ -756,7 +742,7 @@
mBlockIter.advance();
mbuf->release();
- return err;
+ return AMEDIA_ERROR_UNKNOWN;
}
mPendingFrames.push_back(mbuf);
@@ -764,10 +750,10 @@
mBlockIter.advance();
- return OK;
+ return AMEDIA_OK;
}
-status_t MatroskaSource::read(
+media_status_t MatroskaSource::read(
MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
@@ -777,7 +763,7 @@
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
if (mode == ReadOptions::SEEK_FRAME_INDEX) {
- return ERROR_UNSUPPORTED;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
if (!mExtractor->isLiveStreaming()) {
@@ -795,7 +781,7 @@
}
while (mPendingFrames.empty()) {
- status_t err = readBlock();
+ media_status_t err = readBlock();
if (err != OK) {
clearPendingFrames();
@@ -815,7 +801,7 @@
*out = frame;
- return OK;
+ return AMEDIA_OK;
}
// Each input frame contains one or more NAL fragments, each fragment
@@ -854,7 +840,7 @@
frame->release();
frame = NULL;
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
} else if (srcOffset + mNALSizeLen + NALsize > srcSize) {
break;
}
@@ -882,7 +868,7 @@
frame->release();
frame = NULL;
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
if (pass == 0) {
@@ -920,7 +906,7 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
////////////////////////////////////////////////////////////////////////////////
@@ -1006,7 +992,7 @@
return mTracks.size();
}
-MediaTrackHelper *MatroskaExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MatroskaExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
@@ -1014,11 +1000,11 @@
return new MatroskaSource(this, index);
}
-status_t MatroskaExtractor::getTrackMetaData(
- MetaDataBase &meta,
+media_status_t MatroskaExtractor::getTrackMetaData(
+ AMediaFormat *meta,
size_t index, uint32_t flags) {
if (index >= mTracks.size()) {
- return UNKNOWN_ERROR;
+ return AMEDIA_ERROR_UNKNOWN;
}
if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
@@ -1027,8 +1013,7 @@
mExtractedThumbnails = true;
}
- meta = mTracks.itemAt(index).mMeta;
- return OK;
+ return AMediaFormat_copy(meta, mTracks.itemAt(index).mMeta);
}
bool MatroskaExtractor::isLiveStreaming() const {
@@ -1063,7 +1048,7 @@
}
static void addESDSFromCodecPrivate(
- MetaDataBase &meta,
+ AMediaFormat *meta,
bool isAudio, const void *priv, size_t privSize) {
int privSizeBytesRequired = bytesForSize(privSize);
@@ -1091,14 +1076,14 @@
storeSize(esds, idx, privSize);
memcpy(esds + idx, priv, privSize);
- meta.setData(kKeyESDS, 0, esds, esdsSize);
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, priv, privSize);
delete[] esds;
esds = NULL;
}
status_t addVorbisCodecInfo(
- MetaDataBase &meta,
+ AMediaFormat *meta,
const void *_codecPrivate, size_t codecPrivateSize) {
// hexdump(_codecPrivate, codecPrivateSize);
@@ -1156,7 +1141,8 @@
if (codecPrivate[offset] != 0x01) {
return ERROR_MALFORMED;
}
- meta.setData(kKeyVorbisInfo, 0, &codecPrivate[offset], len1);
+ // formerly kKeyVorbisInfo
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, &codecPrivate[offset], len1);
offset += len1;
if (codecPrivate[offset] != 0x03) {
@@ -1168,19 +1154,20 @@
return ERROR_MALFORMED;
}
- meta.setData(
- kKeyVorbisBooks, 0, &codecPrivate[offset],
- codecPrivateSize - offset);
+ // formerly kKeyVorbisBooks
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_1,
+ &codecPrivate[offset], codecPrivateSize - offset);
return OK;
}
static status_t addFlacMetadata(
- MetaDataBase &meta,
+ AMediaFormat *meta,
const void *codecPrivate, size_t codecPrivateSize) {
// hexdump(codecPrivate, codecPrivateSize);
- meta.setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize);
+ // formerly kKeyFlacMetadata
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
int32_t maxInputSize = 64 << 10;
FLACDecoder *flacDecoder = FLACDecoder::Create();
@@ -1202,7 +1189,7 @@
* streamInfo.max_blocksize * streamInfo.channels;
}
}
- meta.setInt32(kKeyMaxInputSize, maxInputSize);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, maxInputSize);
delete flacDecoder;
return OK;
@@ -1253,7 +1240,7 @@
}
void MatroskaExtractor::getColorInformation(
- const mkvparser::VideoTrack *vtrack, MetaDataBase &meta) {
+ const mkvparser::VideoTrack *vtrack, AMediaFormat *meta) {
const mkvparser::Colour *color = vtrack->GetColour();
if (color == NULL) {
return;
@@ -1262,7 +1249,7 @@
// Color Aspects
{
int32_t primaries = 2; // ISO unspecified
- int32_t transfer = 2; // ISO unspecified
+ int32_t isotransfer = 2; // ISO unspecified
int32_t coeffs = 2; // ISO unspecified
bool fullRange = false; // default
bool rangeSpecified = false;
@@ -1271,7 +1258,7 @@
primaries = color->primaries;
}
if (isValidInt32ColourValue(color->transfer_characteristics)) {
- transfer = color->transfer_characteristics;
+ isotransfer = color->transfer_characteristics;
}
if (isValidInt32ColourValue(color->matrix_coefficients)) {
coeffs = color->matrix_coefficients;
@@ -1284,14 +1271,21 @@
rangeSpecified = true;
}
- ColorAspects aspects;
- ColorUtils::convertIsoColorAspectsToCodecAspects(
- primaries, transfer, coeffs, fullRange, aspects);
- meta.setInt32(kKeyColorPrimaries, aspects.mPrimaries);
- meta.setInt32(kKeyTransferFunction, aspects.mTransfer);
- meta.setInt32(kKeyColorMatrix, aspects.mMatrixCoeffs);
- meta.setInt32(
- kKeyColorRange, rangeSpecified ? aspects.mRange : ColorAspects::RangeUnspecified);
+ int32_t range = 0;
+ int32_t standard = 0;
+ int32_t transfer = 0;
+ ColorUtils::convertIsoColorAspectsToPlatformAspects(
+ primaries, isotransfer, coeffs, fullRange,
+ &range, &standard, &transfer);
+ if (range != 0) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_RANGE, range);
+ }
+ if (standard != 0) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_STANDARD, standard);
+ }
+ if (transfer != 0) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_TRANSFER, transfer);
+ }
}
// HDR Static Info
@@ -1335,13 +1329,13 @@
// Only advertise static info if at least one of the groups have been specified.
if (memcmp(&info, &nullInfo, sizeof(info)) != 0) {
info.mID = HDRStaticInfo::kType1;
- meta.setData(kKeyHdrStaticInfo, 'hdrS', &info, sizeof(info));
+ ColorUtils::setHDRStaticInfoIntoAMediaFormat(info, meta);
}
}
}
status_t MatroskaExtractor::initTrackInfo(
- const mkvparser::Track *track, MetaDataBase &meta, TrackInfo *trackInfo) {
+ const mkvparser::Track *track, AMediaFormat *meta, TrackInfo *trackInfo) {
trackInfo->mTrackNum = track->GetNumber();
trackInfo->mMeta = meta;
trackInfo->mExtractor = this;
@@ -1355,7 +1349,8 @@
for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
const mkvparser::ContentEncoding::ContentEncryption *encryption;
encryption = encoding->GetEncryptionByIndex(j);
- trackInfo->mMeta.setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+ AMediaFormat_setBuffer(trackInfo->mMeta,
+ AMEDIAFORMAT_KEY_CRYPTO_KEY, encryption->key_id, encryption->key_id_len);
trackInfo->mEncrypted = true;
break;
}
@@ -1404,9 +1399,10 @@
enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
- MetaDataBase meta;
+ AMediaFormat *meta = AMediaFormat_new();
status_t err = OK;
+ int32_t nalSize = -1;
switch (track->GetType()) {
case VIDEO_TRACK:
@@ -1415,20 +1411,28 @@
static_cast<const mkvparser::VideoTrack *>(track);
if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- meta.setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_AVC, codecPrivate, codecPrivateSize);
+ if (codecPrivateSize > 4) {
+ nalSize = 1 + (codecPrivate[4] & 3);
+ }
} else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
if (codecPrivateSize > 0) {
- meta.setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize);
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_HEVC, codecPrivate, codecPrivateSize);
+ if (codecPrivateSize > 14 + 7) {
+ nalSize = 1 + (codecPrivate[14 + 7] & 3);
+ }
} else {
ALOGW("HEVC is detected, but does not have configuration.");
continue;
}
} else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
if (codecPrivateSize > 0) {
- meta.setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
addESDSFromCodecPrivate(
meta, false, codecPrivate, codecPrivateSize);
} else {
@@ -1437,15 +1441,14 @@
continue;
}
} else if (!strcmp("V_VP8", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP8);
} else if (!strcmp("V_VP9", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP9);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP9);
if (codecPrivateSize > 0) {
// 'csd-0' for VP9 is the Blob of Codec Private data as
// specified in http://www.webmproject.org/vp9/profiles/.
- meta.setData(
- kKeyVp9CodecPrivate, 0, codecPrivate,
- codecPrivateSize);
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
}
} else {
ALOGW("%s is not supported.", codecID);
@@ -1462,8 +1465,8 @@
ALOGW("track height exceeds int32_t, %lld", height);
continue;
}
- meta.setInt32(kKeyWidth, (int32_t)width);
- meta.setInt32(kKeyHeight, (int32_t)height);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, (int32_t)width);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, (int32_t)height);
// setting display width/height is optional
const long long displayUnit = vtrack->GetDisplayUnit();
@@ -1473,8 +1476,10 @@
&& displayHeight > 0 && displayHeight <= INT32_MAX) {
switch (displayUnit) {
case 0: // pixels
- meta.setInt32(kKeyDisplayWidth, (int32_t)displayWidth);
- meta.setInt32(kKeyDisplayHeight, (int32_t)displayHeight);
+ AMediaFormat_setInt32(meta,
+ AMEDIAFORMAT_KEY_DISPLAY_WIDTH, (int32_t)displayWidth);
+ AMediaFormat_setInt32(meta,
+ AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, (int32_t)displayHeight);
break;
case 1: // centimeters
case 2: // inches
@@ -1488,8 +1493,10 @@
const long long computedHeight =
std::max(height, width * displayHeight / displayWidth);
if (computedWidth <= INT32_MAX && computedHeight <= INT32_MAX) {
- meta.setInt32(kKeyDisplayWidth, (int32_t)computedWidth);
- meta.setInt32(kKeyDisplayHeight, (int32_t)computedHeight);
+ AMediaFormat_setInt32(meta,
+ AMEDIAFORMAT_KEY_DISPLAY_WIDTH, (int32_t)computedWidth);
+ AMediaFormat_setInt32(meta,
+ AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, (int32_t)computedHeight);
}
break;
}
@@ -1509,34 +1516,39 @@
static_cast<const mkvparser::AudioTrack *>(track);
if (!strcmp("A_AAC", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
CHECK(codecPrivateSize >= 2);
addESDSFromCodecPrivate(
meta, true, codecPrivate, codecPrivateSize);
} else if (!strcmp("A_VORBIS", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_VORBIS);
err = addVorbisCodecInfo(
meta, codecPrivate, codecPrivateSize);
} else if (!strcmp("A_OPUS", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
- meta.setData(kKeyOpusHeader, 0, codecPrivate, codecPrivateSize);
- meta.setInt64(kKeyOpusCodecDelay, track->GetCodecDelay());
- meta.setInt64(kKeyOpusSeekPreRoll, track->GetSeekPreRoll());
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_OPUS);
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
+ int64_t codecDelay = track->GetCodecDelay();
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_1, &codecDelay, sizeof(codecDelay));
mSeekPreRollNs = track->GetSeekPreRoll();
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_2, &mSeekPreRollNs, sizeof(mSeekPreRollNs));
} else if (!strcmp("A_MPEG/L3", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
} else if (!strcmp("A_FLAC", codecID)) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
} else {
ALOGW("%s is not supported.", codecID);
continue;
}
- meta.setInt32(kKeySampleRate, atrack->GetSamplingRate());
- meta.setInt32(kKeyChannelCount, atrack->GetChannels());
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
break;
}
@@ -1549,7 +1561,7 @@
char lang[4];
strncpy(lang, language, 3);
lang[3] = '\0';
- meta.setCString(kKeyMediaLanguage, lang);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_LANGUAGE, lang);
}
if (err != OK) {
@@ -1558,12 +1570,13 @@
}
long long durationNs = mSegment->GetDuration();
- meta.setInt64(kKeyDuration, (durationNs + 500) / 1000);
+ AMediaFormat_setInt64(meta, AMEDIAFORMAT_KEY_DURATION, (durationNs + 500) / 1000);
mTracks.push();
size_t n = mTracks.size() - 1;
TrackInfo *trackInfo = &mTracks.editItemAt(n);
initTrackInfo(track, meta, trackInfo);
+ trackInfo->mNalLengthSize = nalSize;
if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
// Attempt to recover from AVC track without codec private data
@@ -1580,7 +1593,7 @@
TrackInfo *info = &mTracks.editItemAt(i);
const char *mime;
- CHECK(info->mMeta.findCString(kKeyMIMEType, &mime));
+ CHECK(AMediaFormat_getString(info->mMeta, AMEDIAFORMAT_KEY_MIME, &mime));
if (strncasecmp(mime, "video/", 6)) {
continue;
@@ -1606,16 +1619,16 @@
}
iter.advance();
}
- info->mMeta.setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+ AMediaFormat_setInt64(info->mMeta,
+ AMEDIAFORMAT_KEY_THUMBNAIL_TIME, thumbnailTimeUs);
}
}
-status_t MatroskaExtractor::getMetaData(MetaDataBase &meta) {
- meta.setCString(
- kKeyMIMEType,
- mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+media_status_t MatroskaExtractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
- return OK;
+ return AMEDIA_OK;
}
uint32_t MatroskaExtractor::flags() const {
@@ -1647,22 +1660,22 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
1,
"Matroska Extractor",
{
- [](
+ .v2 = [](
CDataSource *source,
float *confidence,
void **,
- FreeMetaFunc *) -> CreatorFunc {
+ FreeMetaFunc *) -> CreatorFuncV2 {
DataSourceHelper helper(source);
if (SniffMatroska(&helper, confidence)) {
return [](
CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+ void *) -> CMediaExtractorV2* {
+ return wrapV2(new MatroskaExtractor(new DataSourceHelper(source)));};
}
return NULL;
}
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 03fdeee..2fa8881 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -22,7 +22,7 @@
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -35,16 +35,16 @@
struct DataSourceBaseReader;
struct MatroskaSource;
-struct MatroskaExtractor : public MediaExtractorPluginHelper {
+struct MatroskaExtractor : public MediaExtractorPluginHelperV2 {
explicit MatroskaExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrackHelper *getTrack(size_t index);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ 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 uint32_t flags() const;
@@ -58,9 +58,17 @@
friend struct BlockIterator;
struct TrackInfo {
+ TrackInfo() {
+ mMeta = NULL;
+ }
+ ~TrackInfo() {
+ if (mMeta) {
+ AMediaFormat_delete(mMeta);
+ }
+ }
unsigned long mTrackNum;
bool mEncrypted;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
const MatroskaExtractor *mExtractor;
Vector<const mkvparser::CuePoint*> mCuePoints;
@@ -89,13 +97,13 @@
status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
status_t initTrackInfo(
const mkvparser::Track *track,
- MetaDataBase &meta,
+ AMediaFormat *meta,
TrackInfo *trackInfo);
void addTracks();
void findThumbnails();
void getColorInformation(
const mkvparser::VideoTrack *vtrack,
- MetaDataBase &meta);
+ AMediaFormat *meta);
bool isLiveStreaming() const;
MatroskaExtractor(const MatroskaExtractor &);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index eec0392..524d02f 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 {
@@ -4935,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);
@@ -5285,14 +5316,7 @@
// Whole NAL units are returned but each fragment is prefixed by
// the start code (0x00 00 00 01).
ssize_t num_bytes_read = 0;
- int32_t drm = 0;
- bool usesDRM = (mFormat.findInt32(kKeyIsDRM, &drm) && drm != 0);
- if (usesDRM) {
- num_bytes_read =
- mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
- } else {
- num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
- }
+ num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -5301,57 +5325,51 @@
return ERROR_IO;
}
- if (usesDRM) {
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, size);
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
- } else {
- uint8_t *dstData = (uint8_t *)mBuffer->data();
- size_t srcOffset = 0;
- size_t dstOffset = 0;
-
- while (srcOffset < size) {
- bool isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
- size_t nalLength = 0;
- if (!isMalFormed) {
- nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
- srcOffset += mNALLengthSize;
- isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength);
- }
-
- if (isMalFormed) {
- ALOGE("Video is malformed");
- mBuffer->release();
- mBuffer = NULL;
- return ERROR_MALFORMED;
- }
-
- if (nalLength == 0) {
- continue;
- }
-
- if (dstOffset > SIZE_MAX - 4 ||
- dstOffset + 4 > SIZE_MAX - nalLength ||
- dstOffset + 4 + nalLength > mBuffer->size()) {
- ALOGE("b/27208621 : %zu %zu", dstOffset, mBuffer->size());
- android_errorWriteLog(0x534e4554, "27208621");
- mBuffer->release();
- mBuffer = NULL;
- return ERROR_MALFORMED;
- }
-
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 1;
- memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
- srcOffset += nalLength;
- dstOffset += nalLength;
+ while (srcOffset < size) {
+ bool isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
+ size_t nalLength = 0;
+ if (!isMalFormed) {
+ nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
+ srcOffset += mNALLengthSize;
+ isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength);
}
- CHECK_EQ(srcOffset, size);
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, dstOffset);
+
+ if (isMalFormed) {
+ ALOGE("Video is malformed");
+ mBuffer->release();
+ mBuffer = NULL;
+ return ERROR_MALFORMED;
+ }
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ if (dstOffset > SIZE_MAX - 4 ||
+ dstOffset + 4 > SIZE_MAX - nalLength ||
+ dstOffset + 4 + nalLength > mBuffer->size()) {
+ ALOGE("b/27208621 : %zu %zu", dstOffset, mBuffer->size());
+ android_errorWriteLog(0x534e4554, "27208621");
+ mBuffer->release();
+ mBuffer = NULL;
+ return ERROR_MALFORMED;
+ }
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
}
+ CHECK_EQ(srcOffset, size);
+ CHECK(mBuffer != NULL);
+ mBuffer->set_range(0, dstOffset);
mBuffer->meta_data().clear();
mBuffer->meta_data().setInt64(
@@ -5368,6 +5386,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) {
@@ -5566,6 +5590,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) {
@@ -5626,24 +5656,14 @@
// Whole NAL units are returned but each fragment is prefixed by
// the start code (0x00 00 00 01).
ssize_t num_bytes_read = 0;
- int32_t drm = 0;
- bool usesDRM = (mFormat.findInt32(kKeyIsDRM, &drm) && drm != 0);
void *data = NULL;
bool isMalFormed = false;
- if (usesDRM) {
- if (mBuffer == NULL || !isInRange((size_t)0u, mBuffer->size(), size)) {
- isMalFormed = true;
- } else {
- data = mBuffer->data();
- }
+ int32_t max_size;
+ if (!mFormat.findInt32(kKeyMaxInputSize, &max_size)
+ || !isInRange((size_t)0u, (size_t)max_size, size)) {
+ isMalFormed = true;
} else {
- int32_t max_size;
- if (!mFormat.findInt32(kKeyMaxInputSize, &max_size)
- || !isInRange((size_t)0u, (size_t)max_size, size)) {
- isMalFormed = true;
- } else {
- data = mSrcBuffer;
- }
+ data = mSrcBuffer;
}
if (isMalFormed || data == NULL) {
@@ -5664,59 +5684,53 @@
return ERROR_IO;
}
- if (usesDRM) {
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, size);
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
- } else {
- uint8_t *dstData = (uint8_t *)mBuffer->data();
- size_t srcOffset = 0;
- size_t dstOffset = 0;
-
- while (srcOffset < size) {
- isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
- size_t nalLength = 0;
- if (!isMalFormed) {
- nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
- srcOffset += mNALLengthSize;
- isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
- || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
- || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
- }
-
- if (isMalFormed) {
- ALOGE("Video is malformed; nalLength %zu", nalLength);
- mBuffer->release();
- mBuffer = NULL;
- return ERROR_MALFORMED;
- }
-
- if (nalLength == 0) {
- continue;
- }
-
- if (dstOffset > SIZE_MAX - 4 ||
- dstOffset + 4 > SIZE_MAX - nalLength ||
- dstOffset + 4 + nalLength > mBuffer->size()) {
- ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
- android_errorWriteLog(0x534e4554, "26365349");
- mBuffer->release();
- mBuffer = NULL;
- return ERROR_MALFORMED;
- }
-
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 0;
- dstData[dstOffset++] = 1;
- memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
- srcOffset += nalLength;
- dstOffset += nalLength;
+ while (srcOffset < size) {
+ isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
+ size_t nalLength = 0;
+ if (!isMalFormed) {
+ nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
+ srcOffset += mNALLengthSize;
+ isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
+ || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
+ || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
}
- CHECK_EQ(srcOffset, size);
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, dstOffset);
+
+ if (isMalFormed) {
+ ALOGE("Video is malformed; nalLength %zu", nalLength);
+ mBuffer->release();
+ mBuffer = NULL;
+ return ERROR_MALFORMED;
+ }
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ if (dstOffset > SIZE_MAX - 4 ||
+ dstOffset + 4 > SIZE_MAX - nalLength ||
+ dstOffset + 4 + nalLength > mBuffer->size()) {
+ ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
+ android_errorWriteLog(0x534e4554, "26365349");
+ mBuffer->release();
+ mBuffer = NULL;
+ return ERROR_MALFORMED;
+ }
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
}
+ CHECK_EQ(srcOffset, size);
+ CHECK(mBuffer != NULL);
+ mBuffer->set_range(0, dstOffset);
mBuffer->meta_data().setInt64(
kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 1b4fe27..a52ccb1 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -84,7 +84,7 @@
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();
@@ -145,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
@@ -153,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);
@@ -177,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);
}
@@ -189,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 {
@@ -207,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;
@@ -270,10 +270,10 @@
}
MediaBufferBase *packet;
- status_t err = mExtractor->mImpl->readNextPacket(&packet);
+ media_status_t err = mExtractor->mImpl->readNextPacket(&packet);
- if (err != OK) {
- return AMEDIA_ERROR_UNKNOWN;
+ if (err != AMEDIA_OK) {
+ return err;
}
#if 0
@@ -507,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]);
@@ -544,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;;
@@ -567,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
@@ -577,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;
@@ -603,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;
}
@@ -625,7 +625,7 @@
uint32_t frames = getNumSamplesInPacket(*out);
mCurGranulePosition += frames;
- return OK;
+ return AMEDIA_OK;
}
uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
@@ -674,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;
@@ -711,7 +711,7 @@
buffer->release();
}
ALOGE("b/36592202");
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
if (tmp == NULL) {
@@ -719,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());
@@ -739,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);
@@ -776,7 +776,7 @@
}
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
// fall through, the buffer now contains the start of the packet.
@@ -795,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
@@ -827,7 +827,7 @@
*out = buffer;
- return OK;
+ return AMEDIA_OK;
}
}
}
@@ -836,18 +836,18 @@
status_t MyOggExtractor::init() {
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;
}
}
@@ -872,7 +872,7 @@
buildTableOfContents();
}
- return OK;
+ return AMEDIA_OK;
}
void MyOggExtractor::buildTableOfContents() {
@@ -954,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.
@@ -963,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();
@@ -977,7 +977,7 @@
if (size < kOpusHeaderSize
|| memcmp(data, "OpusHead", 8)
|| /* version = */ data[8] != 1) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
mChannelCount = data[9];
@@ -987,22 +987,21 @@
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);
- // are these actually used anywhere?
- // (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
- AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
- AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
- mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
+ 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,
@@ -1031,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;
@@ -1049,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) {
@@ -1063,7 +1062,7 @@
}
}
if (framingBitOffset < 0 || framingBitOffset >= commentSize) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
commentData[framingBitOffset] = 1;
@@ -1080,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();
@@ -1095,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;
@@ -1114,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'
@@ -1124,7 +1123,7 @@
case 1:
{
if (0 != _vorbis_unpack_info(&mVi, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
@@ -1154,7 +1153,7 @@
case 3:
{
if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
parseFileMetaData();
@@ -1164,7 +1163,7 @@
case 5:
{
if (0 != _vorbis_unpack_books(&mVi, &bits)) {
- return ERROR_MALFORMED;
+ return AMEDIA_ERROR_MALFORMED;
}
AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
@@ -1172,7 +1171,7 @@
}
}
- return OK;
+ return AMEDIA_OK;
}
uint64_t MyVorbisExtractor::approxBitrate() const {
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 9a329f1..ddc7031 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -311,6 +311,7 @@
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
kAudioEncodingPcm16bit);
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
index d8c5843..5d399b5 100644
--- a/media/libaaudio/examples/input_monitor/Android.bp
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -5,6 +5,7 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
+ pack_relocations: false,
}
cc_test {
@@ -14,4 +15,5 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
+ pack_relocations: false,
}
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
index 5b7d956..53e5020 100644
--- a/media/libaaudio/examples/loopback/Android.bp
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -9,4 +9,5 @@
"libaudioutils",
],
header_libs: ["libaaudio_example_utils"],
+ pack_relocations: false,
}
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index ef9a753..64deb60 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -163,8 +163,7 @@
const float *needle, int needleSize,
LatencyReport *report) {
const double threshold = 0.1;
- printf("measureLatencyFromEchos: haystackSize = %d, needleSize = %d\n",
- haystackSize, needleSize);
+ // printf("%s: haystackSize = %d, needleSize = %d\n", __func__, haystackSize, needleSize);
// Find first peak
int first = (int) (findFirstMatch(haystack,
@@ -181,8 +180,6 @@
needle,
needleSize,
threshold) + 0.5);
-
- printf("measureLatencyFromEchos: first = %d, again at %d\n", first, again);
first = again;
// Allocate results array
@@ -199,7 +196,7 @@
// Add higher harmonics mapped onto lower harmonics.
// This reinforces the "fundamental" echo.
- const int numEchoes = 10;
+ const int numEchoes = 8;
for (int partial = 1; partial < numEchoes; partial++) {
for (int i = 0; i < numCorrelations; i++) {
harmonicSums[i / partial] += correlations[i] / partial;
@@ -216,7 +213,7 @@
maxCorrelation = harmonicSums[i];
sumOfPeaks += maxCorrelation;
peakIndex = i;
- printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+ // printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
}
}
@@ -476,9 +473,13 @@
void report() override {
printf("EchoAnalyzer ---------------\n");
- printf(LOOPBACK_RESULT_TAG "measured.gain = %f\n", mMeasuredLoopGain);
- printf(LOOPBACK_RESULT_TAG "echo.gain = %f\n", mEchoGain);
- printf(LOOPBACK_RESULT_TAG "test.state = %d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "measured.gain = %8f\n", mMeasuredLoopGain);
+ printf(LOOPBACK_RESULT_TAG "echo.gain = %8f\n", mEchoGain);
+ printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "test.state.name = %8s\n", convertStateToText(mState));
+ if (mState == STATE_WAITING_FOR_SILENCE) {
+ printf("WARNING - Stuck waiting for silence. Input may be too noisy!\n");
+ }
if (mMeasuredLoopGain >= 0.9999) {
printf(" ERROR - clipping, turn down volume slightly\n");
} else {
@@ -491,9 +492,12 @@
printf(" ERROR - confidence too low = %f\n", mLatencyReport.confidence);
} else {
double latencyMillis = 1000.0 * mLatencyReport.latencyInFrames / getSampleRate();
- printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n", mLatencyReport.latencyInFrames);
- printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n", latencyMillis);
- printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n", mLatencyReport.confidence);
+ printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n",
+ mLatencyReport.latencyInFrames);
+ printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n",
+ latencyMillis);
+ printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n",
+ mLatencyReport.confidence);
}
}
}
@@ -527,7 +531,7 @@
int numWritten;
int numSamples;
- echo_state_t nextState = mState;
+ echo_state nextState = mState;
switch (mState) {
case STATE_INITIAL_SILENCE:
@@ -553,6 +557,7 @@
// mLoopCounter, peak);
mDownCounter = 8;
mMeasuredLoopGain = peak; // assumes original pulse amplitude is one
+ mSilenceThreshold = peak * 0.1; // scale silence to measured pulse
// Calculate gain that will give us a nice decaying echo.
mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
if (mEchoGain > MAX_ECHO_GAIN) {
@@ -638,7 +643,7 @@
private:
- enum echo_state_t {
+ enum echo_state {
STATE_INITIAL_SILENCE,
STATE_MEASURING_GAIN,
STATE_WAITING_FOR_SILENCE,
@@ -648,6 +653,35 @@
STATE_FAILED
};
+ const char *convertStateToText(echo_state state) {
+ const char *result = "Unknown";
+ switch(state) {
+ case STATE_INITIAL_SILENCE:
+ result = "INIT";
+ break;
+ case STATE_MEASURING_GAIN:
+ result = "GAIN";
+ break;
+ case STATE_WAITING_FOR_SILENCE:
+ result = "SILENCE";
+ break;
+ case STATE_SENDING_PULSE:
+ result = "PULSE";
+ break;
+ case STATE_GATHERING_ECHOS:
+ result = "ECHOS";
+ break;
+ case STATE_DONE:
+ result = "DONE";
+ break;
+ case STATE_FAILED:
+ result = "FAILED";
+ break;
+ }
+ return result;
+ }
+
+
int32_t mDownCounter = 500;
int32_t mLoopCounter = 0;
int32_t mSampleIndex = 0;
@@ -656,7 +690,7 @@
float mMeasuredLoopGain = 0.0f;
float mDesiredEchoGain = 0.95f;
float mEchoGain = 1.0f;
- echo_state_t mState = STATE_INITIAL_SILENCE;
+ echo_state mState = STATE_INITIAL_SILENCE;
AudioRecording mAudioRecording; // contains only the input after the gain detection burst
LatencyReport mLatencyReport;
@@ -680,21 +714,32 @@
void report() override {
printf("SineAnalyzer ------------------\n");
- printf(LOOPBACK_RESULT_TAG "peak.amplitude = %7.5f\n", mPeakAmplitude);
- printf(LOOPBACK_RESULT_TAG "sine.magnitude = %7.5f\n", mMagnitude);
- printf(LOOPBACK_RESULT_TAG "phase.offset = %7.5f\n", mPhaseOffset);
- printf(LOOPBACK_RESULT_TAG "ref.phase = %7.5f\n", mPhase);
- printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated);
- printf(LOOPBACK_RESULT_TAG "sine.period = %6d\n", mSinePeriod);
- printf(LOOPBACK_RESULT_TAG "test.state = %6d\n", mState);
- printf(LOOPBACK_RESULT_TAG "frame.count = %6d\n", mFrameCounter);
+ printf(LOOPBACK_RESULT_TAG "peak.amplitude = %8f\n", mPeakAmplitude);
+ printf(LOOPBACK_RESULT_TAG "sine.magnitude = %8f\n", mMagnitude);
+ printf(LOOPBACK_RESULT_TAG "peak.noise = %8f\n", mPeakNoise);
+ printf(LOOPBACK_RESULT_TAG "rms.noise = %8f\n", mRootMeanSquareNoise);
+ float amplitudeRatio = mMagnitude / mPeakNoise;
+ float signalToNoise = amplitudeRatio * amplitudeRatio;
+ printf(LOOPBACK_RESULT_TAG "signal.to.noise = %8.2f\n", signalToNoise);
+ float signalToNoiseDB = 10.0 * log(signalToNoise);
+ printf(LOOPBACK_RESULT_TAG "signal.to.noise.db = %8.2f\n", signalToNoiseDB);
+ if (signalToNoiseDB < MIN_SNRATIO_DB) {
+ printf("WARNING - signal to noise ratio is too low! < %d dB\n", MIN_SNRATIO_DB);
+ }
+ printf(LOOPBACK_RESULT_TAG "phase.offset = %8.5f\n", mPhaseOffset);
+ printf(LOOPBACK_RESULT_TAG "ref.phase = %8.5f\n", mPhase);
+ printf(LOOPBACK_RESULT_TAG "frames.accumulated = %8d\n", mFramesAccumulated);
+ printf(LOOPBACK_RESULT_TAG "sine.period = %8d\n", mSinePeriod);
+ printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "frame.count = %8d\n", mFrameCounter);
// Did we ever get a lock?
bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
if (!gotLock) {
printf("ERROR - failed to lock on reference sine tone\n");
} else {
// Only print if meaningful.
- printf(LOOPBACK_RESULT_TAG "glitch.count = %6d\n", mGlitchCount);
+ printf(LOOPBACK_RESULT_TAG "glitch.count = %8d\n", mGlitchCount);
+ printf(LOOPBACK_RESULT_TAG "max.glitch = %8f\n", mMaxGlitchDelta);
}
}
@@ -732,15 +777,48 @@
}
for (int i = 0; i < numFrames; i++) {
+ bool sineEnabled = true;
float sample = inputData[i * inputChannelCount];
float sinOut = sinf(mPhase);
switch (mState) {
case STATE_IDLE:
- case STATE_IMMUNE:
- case STATE_WAITING_FOR_SIGNAL:
+ sineEnabled = false;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_MEASURE_NOISE;
+ mDownCounter = NOISE_FRAME_COUNT;
+ }
break;
+ case STATE_MEASURE_NOISE:
+ sineEnabled = false;
+ mPeakNoise = std::max(abs(sample), mPeakNoise);
+ mNoiseSumSquared += sample * sample;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ mRootMeanSquareNoise = sqrt(mNoiseSumSquared / NOISE_FRAME_COUNT);
+ mTolerance = std::max(MIN_TOLERANCE, mPeakNoise * 2.0f);
+ mPhase = 0.0; // prevent spike at start
+ }
+ break;
+
+ case STATE_IMMUNE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ }
+ break;
+
+ case STATE_WAITING_FOR_SIGNAL:
+ if (peak > mThreshold) {
+ mState = STATE_WAITING_FOR_LOCK;
+ //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
+ resetAccumulator();
+ }
+ break;
+
case STATE_WAITING_FOR_LOCK:
mSinAccumulator += sample * sinOut;
mCosAccumulator += sample * cosf(mPhase);
@@ -766,13 +844,14 @@
// printf(" predicted = %f, actual = %f\n", predicted, sample);
float diff = predicted - sample;
- if (fabs(diff) > mTolerance) {
+ float absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff > mTolerance) {
mGlitchCount++;
//printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
// mFrameCounter, mGlitchCount, predicted, sample);
mState = STATE_IMMUNE;
- //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter);
- mDownCounter = mSinePeriod; // Set duration of IMMUNE state.
+ mDownCounter = mSinePeriod * PERIODS_IMMUNE;
}
// Track incoming signal and slowly adjust magnitude to account
@@ -792,44 +871,23 @@
} break;
}
+ float output = 0.0f;
// Output sine wave so we can measure it.
- outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude)
- + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
- // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement);
-
- // advance and wrap phase
- mPhase += mPhaseIncrement;
- if (mPhase > M_PI) {
- mPhase -= (2.0 * M_PI);
+ if (sineEnabled) {
+ output = (sinOut * mOutputAmplitude)
+ + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+ // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement);
+ // advance and wrap phase
+ mPhase += mPhaseIncrement;
+ if (mPhase > M_PI) {
+ mPhase -= (2.0 * M_PI);
+ }
}
+ outputData[i * outputChannelCount] = output;
+
mFrameCounter++;
}
-
- // Do these once per buffer.
- switch (mState) {
- case STATE_IDLE:
- mState = STATE_IMMUNE; // so we can tell when
- break;
- case STATE_IMMUNE:
- mDownCounter -= numFrames;
- if (mDownCounter <= 0) {
- mState = STATE_WAITING_FOR_SIGNAL;
- //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter);
- }
- break;
- case STATE_WAITING_FOR_SIGNAL:
- if (peak > mThreshold) {
- mState = STATE_WAITING_FOR_LOCK;
- //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
- resetAccumulator();
- }
- break;
- case STATE_WAITING_FOR_LOCK:
- case STATE_LOCKED:
- break;
- }
-
}
void resetAccumulator() {
@@ -840,18 +898,24 @@
void reset() override {
mGlitchCount = 0;
- mState = STATE_IMMUNE;
- mDownCounter = IMMUNE_FRAME_COUNT;
+ mState = STATE_IDLE;
+ mDownCounter = IDLE_FRAME_COUNT;
mPhaseIncrement = 2.0 * M_PI / mSinePeriod;
printf("phaseInc = %f for period %d\n", mPhaseIncrement, mSinePeriod);
resetAccumulator();
mProcessCount = 0;
+ mPeakNoise = 0.0f;
+ mNoiseSumSquared = 0.0;
+ mRootMeanSquareNoise = 0.0;
+ mPhase = 0.0f;
+ mMaxGlitchDelta = 0.0;
}
private:
enum sine_state_t {
STATE_IDLE,
+ STATE_MEASURE_NOISE,
STATE_IMMUNE,
STATE_WAITING_FOR_SIGNAL,
STATE_WAITING_FOR_LOCK,
@@ -859,10 +923,16 @@
};
enum constants {
- IMMUNE_FRAME_COUNT = 48 * 500,
- PERIODS_NEEDED_FOR_LOCK = 8
+ // Arbitrary durations, assuming 48000 Hz
+ IDLE_FRAME_COUNT = 48 * 100,
+ NOISE_FRAME_COUNT = 48 * 600,
+ PERIODS_NEEDED_FOR_LOCK = 8,
+ PERIODS_IMMUNE = 2,
+ MIN_SNRATIO_DB = 65
};
+ static constexpr float MIN_TOLERANCE = 0.01;
+
int mSinePeriod = 79;
double mPhaseIncrement = 0.0;
double mPhase = 0.0;
@@ -870,17 +940,23 @@
double mPreviousPhaseOffset = 0.0;
double mMagnitude = 0.0;
double mThreshold = 0.005;
- double mTolerance = 0.01;
+ double mTolerance = MIN_TOLERANCE;
int32_t mFramesAccumulated = 0;
int32_t mProcessCount = 0;
double mSinAccumulator = 0.0;
double mCosAccumulator = 0.0;
+ float mMaxGlitchDelta = 0.0f;
int32_t mGlitchCount = 0;
double mPeakAmplitude = 0.0;
- int mDownCounter = IMMUNE_FRAME_COUNT;
+ int mDownCounter = IDLE_FRAME_COUNT;
int32_t mFrameCounter = 0;
float mOutputAmplitude = 0.75;
+ // measure background noise
+ float mPeakNoise = 0.0f;
+ double mNoiseSumSquared = 0.0;
+ double mRootMeanSquareNoise = 0.0;
+
PseudoRandom mWhiteNoise;
float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 84f9c22..124efd8 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -37,13 +37,12 @@
// Tag for machine readable results as property = value pairs
#define RESULT_TAG "RESULT: "
-#define NUM_SECONDS 5
-#define PERIOD_MILLIS 1000
-#define NUM_INPUT_CHANNELS 1
#define FILENAME_ALL "/data/loopback_all.wav"
#define FILENAME_ECHOS "/data/loopback_echos.wav"
-#define APP_VERSION "0.2.04"
+#define APP_VERSION "0.3.00"
+constexpr int kLogPeriodMillis = 1000;
+constexpr int kNumInputChannels = 1;
constexpr int kNumCallbacksToDrain = 20;
constexpr int kNumCallbacksToDiscard = 20;
@@ -336,7 +335,7 @@
aaudio_result_t result = AAUDIO_OK;
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
- int requestedInputChannelCount = NUM_INPUT_CHANNELS;
+ int requestedInputChannelCount = kNumInputChannels;
aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
int32_t requestedInputCapacity = AAUDIO_UNSPECIFIED;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
@@ -459,7 +458,9 @@
argParser.setPerformanceMode(inputPerformanceLevel);
argParser.setChannelCount(requestedInputChannelCount);
argParser.setSharingMode(requestedInputSharingMode);
- // Warning! If you change input capacity then you may not get a FAST track on Legacy path.
+ if (requestedInputCapacity != AAUDIO_UNSPECIFIED) {
+ printf("Warning! If you set input capacity then maybe no FAST track on Legacy path!\n");
+ }
argParser.setBufferCapacity(requestedInputCapacity);
result = recorder.open(argParser);
@@ -510,15 +511,11 @@
// Start OUTPUT first so INPUT does not overflow.
result = player.start();
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
- result, AAudio_convertResultToText(result));
goto finish;
}
result = recorder.start();
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
- result, AAudio_convertResultToText(result));
goto finish;
}
@@ -561,7 +558,7 @@
AAudioStream_getXRunCount(outputStream)
);
}
- int32_t periodMillis = (timeMillis < 2000) ? PERIOD_MILLIS / 4 : PERIOD_MILLIS;
+ int32_t periodMillis = (timeMillis < 2000) ? kLogPeriodMillis / 4 : kLogPeriodMillis;
usleep(periodMillis * 1000);
timeMillis += periodMillis;
}
@@ -586,12 +583,12 @@
if (loopbackData.inputError == AAUDIO_OK) {
if (testMode == TEST_SINE_MAGNITUDE) {
printAudioGraph(loopbackData.audioRecording, 200);
+ // Print again so we don't have to scroll past waveform.
+ printf("OUTPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(outputStream);
+ printf("INPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(inputStream);
}
- // Print again so we don't have to scroll past waveform.
- printf("OUTPUT Stream ----------------------------------------\n");
- argParser.compareWithStream(outputStream);
- printf("INPUT Stream ----------------------------------------\n");
- argParser.compareWithStream(inputStream);
loopbackData.loopbackProcessor->report();
}
@@ -600,21 +597,21 @@
int32_t framesRead = AAudioStream_getFramesRead(inputStream);
int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
printf("Callback Results ---------------------------------------- INPUT\n");
- printf(" input overruns = %d\n", AAudioStream_getXRunCount(inputStream));
+ printf(" input overruns = %8d\n", AAudioStream_getXRunCount(inputStream));
printf(" framesWritten = %8d\n", framesWritten);
printf(" framesRead = %8d\n", framesRead);
printf(" myFramesRead = %8d\n", (int) loopbackData.framesReadTotal);
printf(" written - read = %8d\n", (int) (framesWritten - framesRead));
printf(" insufficient # = %8d\n", (int) loopbackData.insufficientReadCount);
if (loopbackData.insufficientReadCount > 0) {
- printf(" insufficient frames = %8d\n", (int) loopbackData.insufficientReadFrames);
+ printf(" insuffic. frames = %8d\n", (int) loopbackData.insufficientReadFrames);
}
}
{
int32_t framesRead = AAudioStream_getFramesRead(outputStream);
int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
printf("Callback Results ---------------------------------------- OUTPUT\n");
- printf(" output underruns = %d\n", AAudioStream_getXRunCount(outputStream));
+ printf(" output underruns = %8d\n", AAudioStream_getXRunCount(outputStream));
printf(" myFramesWritten = %8d\n", (int) loopbackData.framesWrittenTotal);
printf(" framesWritten = %8d\n", framesWritten);
printf(" framesRead = %8d\n", framesRead);
@@ -659,4 +656,3 @@
return EXIT_SUCCESS;
}
}
-
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 54b77ba..1645986 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -193,7 +193,7 @@
aaudio_result_t start() {
aaudio_result_t result = AAudioStream_requestStart(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestStart(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
@@ -203,7 +203,7 @@
aaudio_result_t stop() {
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestStop(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -215,7 +215,7 @@
aaudio_result_t pause() {
aaudio_result_t result = AAudioStream_requestPause(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestPause(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -223,11 +223,27 @@
return result;
}
+ aaudio_result_t waitUntilPaused() {
+ aaudio_result_t result = AAUDIO_OK;
+ aaudio_stream_state_t currentState = AAudioStream_getState(mStream);
+ aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
+ while (result == AAUDIO_OK && currentState == AAUDIO_STREAM_STATE_PAUSING) {
+ result = AAudioStream_waitForStateChange(mStream, inputState,
+ ¤tState, NANOS_PER_SECOND);
+ inputState = currentState;
+ }
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+ return (currentState == AAUDIO_STREAM_STATE_PAUSED)
+ ? AAUDIO_OK : AAUDIO_ERROR_INVALID_STATE;
+ }
+
// Flush the stream. AAudio will stop calling your callback function.
aaudio_result_t flush() {
aaudio_result_t result = AAudioStream_requestFlush(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestFlush(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 869fad0..246e2d7 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -201,8 +201,10 @@
aaudio_result_t start() {
aaudio_result_t result = AAudioStream_requestStart(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
+ fprintf(stderr, " Did you remember to enter: adb root ????\n");
+
}
return result;
}
@@ -211,8 +213,9 @@
aaudio_result_t stop() {
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestStop(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
+
}
return result;
}
@@ -221,7 +224,7 @@
aaudio_result_t pause() {
aaudio_result_t result = AAudioStream_requestPause(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestPause(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
index aa25e67..cc80861 100644
--- a/media/libaaudio/examples/write_sine/Android.bp
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -4,6 +4,7 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
+ pack_relocations: false,
}
cc_test {
@@ -12,4 +13,5 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
+ pack_relocations: false,
}
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index e33e9f8..7a48153 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -30,6 +30,8 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
+#define APP_VERSION "0.1.5"
+
/**
* Open stream, play some sine waves, then close the stream.
*
@@ -109,13 +111,13 @@
startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < durationSeconds; second++) {
// Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
- long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
int64_t millis =
(getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
result = myData.waker.get();
- printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ printf(" waker result = %d, at %6d millis"
", second = %3d, framesWritten = %8d, underruns = %d\n",
- ret, result, (int) millis,
+ result, (int) millis,
second,
(int) AAudioStream_getFramesWritten(player.getStream()),
(int) AAudioStream_getXRunCount(player.getStream()));
@@ -138,6 +140,10 @@
if (result != AAUDIO_OK) {
goto error;
}
+ result = player.waitUntilPaused();
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
result = player.flush();
}
if (result != AAUDIO_OK) {
@@ -219,7 +225,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback V0.1.4\n", argv[0]);
+ printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
for (int i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8dc31d0..e272f2a 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -146,14 +146,14 @@
AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
int32_t channelCount)
{
- AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- streamBuilder->setSamplesPerFrame(channelCount);
+ AAudioStreamBuilder_setSamplesPerFrame(builder, channelCount);
}
AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
- int32_t channelCount)
+ int32_t samplesPerFrame)
{
- AAudioStreamBuilder_setChannelCount(builder, channelCount);
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setSamplesPerFrame(samplesPerFrame);
}
AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index c86d4ce..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
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/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 3534149..35e2f3d 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -9,6 +9,7 @@
LOCAL_CFLAGS+= -O2 -fvisibility=hidden
LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DBUILD_FLOAT -DSUPPORT_MC
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e2ccfb7..00bc371 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -32,8 +32,6 @@
#include <audio_effects/effect_visualizer.h>
#include <audio_utils/primitives.h>
-#define BUILD_FLOAT
-
#ifdef BUILD_FLOAT
static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
@@ -157,7 +155,12 @@
if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
- if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
+ const uint32_t channelCount = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
+#ifdef SUPPORT_MC
+ if (channelCount < 1 || channelCount > FCC_8) return -EINVAL;
+#else
+ if (channelCount != FCC_2) return -EINVAL;
+#endif
if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
@@ -356,7 +359,7 @@
// store the measurement
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
- rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount);
+ rmsSqAcc / sampleLen;
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true;
if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) {
pContext->mMeasurementBufferIdx = 0;
@@ -375,12 +378,17 @@
#ifdef BUILD_FLOAT
float maxSample = 0.f;
- for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
- maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+ for (size_t inIdx = 0; inIdx < sampleLen; ) {
+ // we reconstruct the actual summed value to ensure proper normalization
+ // for multichannel outputs (channels > 2 may often be 0).
+ float smp = 0.f;
+ for (int i = 0; i < pContext->mChannelCount; ++i) {
+ smp += inBuffer->f32[inIdx++];
+ }
+ maxSample = fmax(maxSample, fabs(smp));
}
if (maxSample > 0.f) {
- constexpr float halfish = 127.f / 256.f;
- fscale = halfish / maxSample;
+ fscale = 127.f / maxSample;
int exp; // unused
const float significand = frexp(fscale, &exp);
if (significand == 0.5f) {
@@ -412,7 +420,8 @@
} else {
assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
#ifdef BUILD_FLOAT
- fscale = 0.5f; // default divide by 2 to account for sum of L + R.
+ // Note: if channels are uncorrelated, 1/sqrt(N) could be used at the risk of clipping.
+ fscale = 1.f / pContext->mChannelCount; // account for summing all the channels together.
#else
shift = 9;
#endif // BUILD_FLOAT
@@ -422,17 +431,19 @@
uint32_t inIdx;
uint8_t *buf = pContext->mCaptureBuf;
for (inIdx = 0, captIdx = pContext->mCaptureIdx;
- inIdx < inBuffer->frameCount;
- inIdx++, captIdx++) {
- if (captIdx >= CAPTURE_BUF_SIZE) {
- // wrap around
- captIdx = 0;
- }
+ inIdx < sampleLen;
+ captIdx++) {
+ if (captIdx >= CAPTURE_BUF_SIZE) captIdx = 0; // wrap
+
#ifdef BUILD_FLOAT
- const float smp = (inBuffer->f32[2 * inIdx] + inBuffer->f32[2 * inIdx + 1]) * fscale;
- buf[captIdx] = clamp8_from_float(smp);
+ float smp = 0.f;
+ for (uint32_t i = 0; i < pContext->mChannelCount; ++i) {
+ smp += inBuffer->f32[inIdx++];
+ }
+ buf[captIdx] = clamp8_from_float(smp * fscale);
#else
- const int32_t smp = (inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]) >> shift;
+ const int32_t smp = (inBuffer->s16[inIdx] + inBuffer->s16[inIdx + 1]) >> shift;
+ inIdx += FCC_2; // integer supports stereo only.
buf[captIdx] = ((uint8_t)smp)^0x80;
#endif // BUILD_FLOAT
}
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 25d28ff..3d9e62e 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -291,6 +291,7 @@
"libmediaextractor",
"libmediandk",
"libnativewindow",
+ "libmediandk_utils",
"libstagefright_foundation",
"libui",
"libutils",
@@ -305,6 +306,10 @@
"media_plugin_headers",
],
+ include_dirs: [
+ "frameworks/av/media/ndk",
+ ],
+
static_libs: [
"libstagefright_rtsp",
"libstagefright_timedtext",
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index 320c7a9..bcc7ebf 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -25,6 +25,7 @@
#include "MediaUtils.h"
extern "C" size_t __cfi_shadow_size();
+extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
namespace android {
@@ -65,6 +66,14 @@
maxMem = propVal;
}
+ // If 64-bit Scudo is in use, enforce the hard RSS limit (in MB).
+ if (maxMem != SIZE_MAX && sizeof(void *) == 8 &&
+ &__scudo_set_rss_limit != 0) {
+ __scudo_set_rss_limit(maxMem >> 20, 1);
+ ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
+ return;
+ }
+
// Increase by the size of the CFI shadow mapping. Most of the shadow is not
// backed with physical pages, and it is possible for the result to be
// higher than total physical memory. This is fine for RLIMIT_AS.
diff --git a/media/libmedia/NdkMediaErrorPriv.cpp b/media/libmedia/NdkMediaErrorPriv.cpp
index d061f5a..ba3b919 100644
--- a/media/libmedia/NdkMediaErrorPriv.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);
@@ -45,6 +51,12 @@
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 9e09c7e..eed96e7 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -31,6 +31,8 @@
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Errors.h>
+#include "NdkMediaDataSourceCallbacksPriv.h"
+
namespace android {
static const size_t kAESBlockSize = 16; // AES_BLOCK_SIZE
@@ -1244,8 +1246,14 @@
return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
}
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
+ : mDataSource(dataSource),
+ mAMediaDataSource(convertDataSourceToAMediaDataSource(dataSource)) {
+}
+
AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
- : mAMediaDataSource(aDataSource) {
+ : mDataSource(NULL),
+ mAMediaDataSource(aDataSource) {
}
AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
diff --git a/media/libmedia/include/media/Crypto.h b/media/libmedia/include/media/Crypto.h
deleted file mode 100644
index b68413d..0000000
--- a/media/libmedia/include/media/Crypto.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRYPTO_H_
-
-#define CRYPTO_H_
-
-#include <media/ICrypto.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-
-#include "SharedLibrary.h"
-
-namespace android {
-
-struct CryptoFactory;
-struct CryptoPlugin;
-
-struct Crypto : public BnCrypto {
- Crypto();
- virtual ~Crypto();
-
- virtual status_t initCheck() const;
-
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
- virtual status_t createPlugin(
- const uint8_t uuid[16], const void *data, size_t size);
-
- virtual status_t destroyPlugin();
-
- virtual bool requiresSecureDecoderComponent(
- const char *mime) const;
-
- virtual void notifyResolution(uint32_t width, uint32_t height);
-
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
- virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const sp<IMemory> &source, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const DestinationBuffer &destination, AString *errorDetailMsg);
-
- virtual void setHeap(const sp<IMemoryHeap>&) {}
- virtual void unsetHeap(const sp<IMemoryHeap>&) {}
-
-private:
- mutable Mutex mLock;
-
- status_t mInitCheck;
- sp<SharedLibrary> mLibrary;
- CryptoFactory *mFactory;
- CryptoPlugin *mPlugin;
-
- static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
- static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
- static Mutex mMapLock;
-
- void findFactoryForScheme(const uint8_t uuid[16]);
- bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
- void closeFactory();
-
- DISALLOW_EVIL_CONSTRUCTORS(Crypto);
-};
-
-} // namespace android
-
-#endif // CRYPTO_H_
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/Drm.h b/media/libmedia/include/media/Drm.h
deleted file mode 100644
index fc869cc..0000000
--- a/media/libmedia/include/media/Drm.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2013 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 DRM_H_
-
-#define DRM_H_
-
-#include "SharedLibrary.h"
-
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class DrmFactory;
-class DrmPlugin;
-struct DrmSessionClientInterface;
-
-struct Drm : public BnDrm,
- public IBinder::DeathRecipient,
- public DrmPluginListener {
- Drm();
- virtual ~Drm();
-
- virtual status_t initCheck() const;
-
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
-
- virtual status_t createPlugin(const uint8_t uuid[16], const String8 &appPackageName);
-
- virtual status_t destroyPlugin();
-
- virtual status_t openSession(Vector<uint8_t> &sessionId);
-
- virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
- virtual status_t
- getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl,
- DrmPlugin::KeyRequestType *keyRequestType);
-
- virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId);
-
- virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
- virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId);
-
- virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const;
-
- virtual status_t getProvisionRequest(String8 const &certType,
- String8 const &certAuthority,
- Vector<uint8_t> &request,
- String8 &defaulUrl);
-
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate,
- Vector<uint8_t> &wrappedKey);
-
- virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
- virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
- virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
- virtual status_t releaseAllSecureStops();
-
- virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
- virtual status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value ) const;
- virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
- virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const;
-
- virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- virtual status_t encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- virtual status_t decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- virtual status_t sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature);
-
- virtual status_t verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match);
-
- virtual status_t signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey,
- Vector<uint8_t> &signature);
-
- virtual status_t setListener(const sp<IDrmClient>& listener);
-
- virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
- Vector<uint8_t> const *sessionId,
- Vector<uint8_t> const *data);
-
- virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
- int64_t expiryTimeInMS);
-
- virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
- Vector<DrmPlugin::KeyStatus> const *keyStatusList,
- bool hasNewUsableKey);
-
- virtual void binderDied(const wp<IBinder> &the_late_who);
-
-private:
- static Mutex mLock;
-
- status_t mInitCheck;
-
- sp<DrmSessionClientInterface> mDrmSessionClient;
-
- sp<IDrmClient> mListener;
- mutable Mutex mEventLock;
- mutable Mutex mNotifyLock;
-
- sp<SharedLibrary> mLibrary;
- DrmFactory *mFactory;
- DrmPlugin *mPlugin;
-
- static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
- static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
- static Mutex mMapLock;
-
- void findFactoryForScheme(const uint8_t uuid[16]);
- bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
- void closeFactory();
- void writeByteArray(Parcel &obj, Vector<uint8_t> const *array);
-
- DISALLOW_EVIL_CONSTRUCTORS(Drm);
-};
-
-} // namespace android
-
-#endif // CRYPTO_H_
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index b3b0688..8a417f6 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -280,13 +280,10 @@
struct AMediaDataSourceWrapper : public RefBase {
+ AMediaDataSourceWrapper(const sp<DataSource>&);
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();
@@ -294,10 +291,8 @@
virtual ~AMediaDataSourceWrapper();
private:
+ sp<DataSource> mDataSource;
AMediaDataSource *mAMediaDataSource;
- int mFd;
- int64_t mOffset;
- int64_t mLength;
DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
};
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index cdef637..d29e97d 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -68,6 +68,11 @@
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,
+ METADATA_KEY_SAMPLERATE = 38,
+ METADATA_KEY_BITS_PER_SAMPLE = 39,
// Add more here...
};
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 0a99974..28b8c2b 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -89,7 +89,6 @@
kKeyMaxHeight = 'maxH',
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
kKeyTrackID = 'trID',
- kKeyIsDRM = 'idrm', // int32_t (bool)
kKeyEncoderDelay = 'encd', // int32_t (frames)
kKeyEncoderPadding = 'encp', // int32_t (frames)
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 3b155c5..480a630 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -404,12 +404,12 @@
return BAD_VALUE;
}
// Microsecond is used in NuPlayer2.
- if (dsd->mStartPositionMs > INT64_MAX / 1000) {
- dsd->mStartPositionMs = INT64_MAX / 1000;
+ if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
+ dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
}
- if (dsd->mEndPositionMs > INT64_MAX / 1000) {
- dsd->mEndPositionMs = INT64_MAX / 1000;
+ 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);
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 6056ad9..1860b0c 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -34,7 +34,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NdkUtils.h>
#include <media/stagefright/Utils.h>
-#include "NdkMediaDataSourceCallbacksPriv.h"
namespace android {
@@ -79,6 +78,7 @@
void NuPlayer2::GenericSource2::resetDataSource() {
ALOGV("resetDataSource");
+ mDisconnected = false;
mUri.clear();
mUriHeaders.clear();
if (mFd >= 0) {
@@ -136,8 +136,7 @@
ALOGV("setDataSource (source: %p)", source.get());
resetDataSource();
- AMediaDataSource *aSource = convertDataSourceToAMediaDataSource(source);
- mDataSourceWrapper = new AMediaDataSourceWrapper(aSource);
+ mDataSourceWrapper = new AMediaDataSourceWrapper(source);
return OK;
}
@@ -196,7 +195,11 @@
}
sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+ if (aSourceWrapper != NULL) {
+ trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
+ } else {
+ trackExtractor->setDataSource(fd, mOffset, mLength);
+ }
const char *mime;
sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 018324e..bc17d13 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -216,6 +216,7 @@
mAudioDecoderGeneration(0),
mVideoDecoderGeneration(0),
mRendererGeneration(0),
+ mEOSMonitorGeneration(0),
mLastStartedPlayingTimeNs(0),
mPreviousSeekTimeUs(0),
mAudioEOS(false),
@@ -586,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) {
@@ -713,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;
@@ -1522,6 +1544,42 @@
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) {
@@ -1675,6 +1733,7 @@
mRenderer->setVideoFrameRate(rate);
}
+ addEndTimeMonitor();
// Renderer is created in paused state.
if (play) {
mRenderer->resume();
@@ -1693,6 +1752,18 @@
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) {
@@ -2473,17 +2544,22 @@
long previousSrcId;
{
Mutex::Autolock autoLock(mSourceLock);
- mCurrentSourceInfo.mSource = mNextSourceInfo.mSource;
- mNextSourceInfo.mSource = NULL;
previousSrcId = mCurrentSourceInfo.mSrcId;
- mCurrentSourceInfo.mSrcId = mNextSourceInfo.mSrcId;
- ++mNextSourceInfo.mSrcId; // to distinguish the two sources.
+
+ 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);
+
+ 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);
}
@@ -2494,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
@@ -2589,37 +2667,50 @@
switch (what) {
case Source::kWhatPrepared:
{
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p",
- mCurrentSourceInfo.mSource.get());
- 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;
- }
-
- 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);
+ 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;
@@ -2665,7 +2756,9 @@
driver->notifyListener(
srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
}
- driver->notifyFlagsChanged(srcId, flags);
+ if (srcId == mCurrentSourceInfo.mSrcId) {
+ driver->notifyFlagsChanged(srcId, flags);
+ }
}
if (srcId == mCurrentSourceInfo.mSrcId) {
@@ -3128,7 +3221,17 @@
mSrcId(0),
mSourceFlags(0),
mStartTimeUs(0),
- mEndTimeUs(INT64_MAX) {
+ 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 4db0cbf..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,8 @@
kWhatSetBufferingSettings = 'sBuS',
kWhatPrepareDrm = 'pDrm',
kWhatReleaseDrm = 'rDrm',
+ kWhatRewind = 'reWd',
+ kWhatEOSMonitor = 'eosM',
};
typedef enum {
@@ -167,6 +170,7 @@
struct SourceInfo {
SourceInfo();
+ SourceInfo &operator=(const SourceInfo &);
sp<Source> mSource;
std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
@@ -194,6 +198,7 @@
int32_t mAudioDecoderGeneration;
int32_t mVideoDecoderGeneration;
int32_t mRendererGeneration;
+ int32_t mEOSMonitorGeneration;
Mutex mPlayingTimeLock;
int64_t mLastStartedPlayingTimeNs;
@@ -302,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/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index a37973b..09b19d7 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -29,6 +29,7 @@
"libmediametrics",
"libmediautils",
"libmemunreachable",
+ "libnetd_client",
"libpowermanager",
"libstagefright",
"libstagefright_foundation",
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 3208d16..d96d358 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -239,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/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0f24329..03e0d12 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -114,30 +114,4 @@
mMaxBandwidthHistoryItems = numHistoryItems;
}
-// static
-void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
- int res = qtaguid_tagSocket(sockfd, kTag, uid);
- if (res != 0) {
- ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
- }
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserTag(int sockfd) {
- int res = qtaguid_untagSocket(sockfd);
- if (res != 0) {
- ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
- }
-}
-
-// static
-void HTTPBase::RegisterSocketUserMark(int sockfd, uid_t uid) {
- setNetworkForUser(uid, sockfd);
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserMark(int sockfd) {
- RegisterSocketUserMark(sockfd, geteuid());
-}
-
} // namespace android
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 5ad5295..9fbb20e 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -135,13 +135,13 @@
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;
}
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 2cf79c3..a3259fd 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -56,6 +56,32 @@
return true;
}
+bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size) {
+ if (meta == nullptr || data == nullptr || size == 0) {
+ return false;
+ }
+
+ int32_t width;
+ int32_t height;
+ int32_t sarWidth;
+ int32_t sarHeight;
+ sp<ABuffer> accessUnit = new ABuffer((void*)data, size);
+ sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
+ if (csd == nullptr) {
+ return false;
+ }
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_AVC, csd->data(), csd->size());
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, width);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, height);
+ if (sarWidth > 0 && sarHeight > 0) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
+ }
+ return true;
+}
+
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
if (data == nullptr || size < 7) {
return false;
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..f34d54c 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 {
@@ -275,12 +276,6 @@
return NO_INIT;
}
- int32_t drm = 0;
- if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
- ALOGE("frame grab not allowed.");
- return ERROR_DRM_UNKNOWN;
- }
-
size_t n = mExtractor->countTracks();
size_t i;
for (i = 0; i < n; ++i) {
@@ -403,6 +398,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();
@@ -531,6 +545,19 @@
if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
audioBitrate = -1;
}
+
+ int32_t bitsPerSample = -1;
+ int32_t sampleRate = -1;
+ trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
+ trackMeta->findInt32(kKeySampleRate, &sampleRate);
+ if (bitsPerSample >= 0) {
+ sprintf(tmp, "%d", bitsPerSample);
+ mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
+ }
+ if (sampleRate >= 0) {
+ sprintf(tmp, "%d", sampleRate);
+ mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
+ }
} else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
hasVideo = true;
@@ -542,6 +569,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 456e2e3..96993e9 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -787,6 +787,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+ int32_t bitsPerSample;
+ if (meta->findInt32(kKeyBitsPerSample, &bitsPerSample)) {
+ msg->setInt32("bits-per-sample", bitsPerSample);
+ }
+
int32_t channelMask;
if (meta->findInt32(kKeyChannelMask, &channelMask)) {
msg->setInt32("channel-mask", channelMask);
@@ -1014,6 +1019,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);
@@ -1476,6 +1531,10 @@
if (msg->findInt32("sample-rate", &sampleRate)) {
meta->setInt32(kKeySampleRate, sampleRate);
}
+ int32_t bitsPerSample;
+ if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
+ meta->setInt32(kKeyBitsPerSample, bitsPerSample);
+ }
int32_t channelMask;
if (msg->findInt32("channel-mask", &channelMask)) {
meta->setInt32(kKeyChannelMask, channelMask);
@@ -1534,7 +1593,7 @@
if (msg->findBuffer("csd-1", &csd1)) {
std::vector<char> avcc(csd0size + csd1->size() + 1024);
size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
- meta->setData(kKeyAVCC, kKeyAVCC, avcc.data(), outsize);
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
}
} else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
std::vector<char> esds(csd0size + 31);
@@ -1546,7 +1605,7 @@
mime == MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) {
std::vector<uint8_t> hvcc(csd0size + 1024);
size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
- meta->setData(kKeyHVCC, kKeyHVCC, hvcc.data(), outsize);
+ meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1563,6 +1622,11 @@
meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
}
}
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_AVC && msg->findBuffer("csd-avc", &csd0)) {
+ meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
+ } else if ((mime == MEDIA_MIMETYPE_VIDEO_HEVC || mime == MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)
+ && msg->findBuffer("csd-hevc", &csd0)) {
+ meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
}
int32_t timeScale;
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/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/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index c4eaa27..070e325 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/NdkMediaFormatPriv.h>
namespace android {
@@ -342,6 +343,14 @@
aspects.mRange = fullRange ? ColorAspects::RangeFull : ColorAspects::RangeLimited;
}
+void ColorUtils::convertIsoColorAspectsToPlatformAspects(
+ int32_t primaries, int32_t intransfer, int32_t coeffs, bool fullRange,
+ int32_t *range, int32_t *standard, int32_t *outtransfer) {
+ ColorAspects aspects;
+ convertIsoColorAspectsToCodecAspects(primaries, intransfer, coeffs, fullRange, aspects);
+ convertCodecColorAspectsToPlatformAspects(aspects, range, standard, outtransfer);
+}
+
// static
ColorAspects ColorUtils::unpackToColorAspects(uint32_t packed) {
ColorAspects aspects;
@@ -684,6 +693,13 @@
transfer, asString((ColorTransfer)transfer));
}
+
+// static
+void ColorUtils::setHDRStaticInfoIntoAMediaFormat(
+ const HDRStaticInfo &info, AMediaFormat *format) {
+ setHDRStaticInfoIntoFormat(info, format->mFormat);
+}
+
// static
void ColorUtils::setHDRStaticInfoIntoFormat(
const HDRStaticInfo &info, sp<AMessage> &format) {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
index d6c768d..cd0af2b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
@@ -27,6 +27,8 @@
#include <media/hardware/VideoAPI.h>
#include <system/graphics.h>
+struct AMediaFormat;
+
namespace android {
struct ColorUtils {
@@ -135,6 +137,9 @@
static void convertIsoColorAspectsToCodecAspects(
int32_t primaries, int32_t transfer, int32_t coeffs, bool fullRange,
ColorAspects &aspects);
+ static void convertIsoColorAspectsToPlatformAspects(
+ int32_t primaries, int32_t isotransfer, int32_t coeffs, bool fullRange,
+ int32_t *range, int32_t *standard, int32_t *transfer);
// unpack a uint32_t to a full ColorAspects struct
static ColorAspects unpackToColorAspects(uint32_t packed);
@@ -180,6 +185,8 @@
// writes |info| into format.
static void setHDRStaticInfoIntoFormat(const HDRStaticInfo &info, sp<AMessage> &format);
+ // writes |info| into format.
+ static void setHDRStaticInfoIntoAMediaFormat(const HDRStaticInfo &info, AMediaFormat *format);
};
inline static const char *asString(android::ColorUtils::ColorStandard i, const char *def = "??") {
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index a924197..8b20187 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -51,12 +51,6 @@
virtual void setBandwidthHistorySize(size_t numHistoryItems);
- static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
- static void UnRegisterSocketUserTag(int sockfd);
-
- static void RegisterSocketUserMark(int sockfd, uid_t uid);
- static void UnRegisterSocketUserMark(int sockfd);
-
virtual String8 toString() {
return mName;
}
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 e87c7f9..dcaf27f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -26,6 +26,7 @@
struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAVCCodecSpecificData(AMediaFormat *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,
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index fb498d4..3debe34 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -552,8 +552,10 @@
hasStreamCA = true;
streamCA.mSystemID = br->getBits(16);
streamCA.mPID = br->getBits(16) & 0x1fff;
- ES_info_length -= 4;
- streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length - 4);
+ ES_info_length -= descriptor_length;
+ descriptor_length -= 4;
+ streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length);
+ br->skipBits(descriptor_length * 8);
} else if (info.mType == STREAMTYPE_PES_PRIVATE_DATA &&
descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
unsigned descTagExt = br->getBits(8);
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 672a37c..f9f7ec2 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -502,7 +502,8 @@
// These values were chosen to prevent integer overflows further down the line, and do
// not indicate support for 32kx32k video.
if (newWidth > 32768 || newHeight > 32768
- || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
+ || video_def->nStride > 32768 || video_def->nStride < -32768
+ || video_def->nSliceHeight > 32768) {
ALOGE("b/22885421");
return OMX_ErrorBadParameter;
}
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 5620cf8..33c1c18 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "ARTSPConnection.h"
+#include "NetworkUtils.h"
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -59,8 +60,8 @@
if (mSocket >= 0) {
ALOGE("Connection is still open, closing the socket.");
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -214,8 +215,8 @@
if (mState != DISCONNECTED) {
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -266,9 +267,9 @@
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mUIDValid) {
- HTTPBase::RegisterSocketUserTag(mSocket, mUID,
+ NetworkUtils::RegisterSocketUserTag(mSocket, mUID,
(uint32_t)*(uint32_t*) "RTSP");
- HTTPBase::RegisterSocketUserMark(mSocket, mUID);
+ NetworkUtils::RegisterSocketUserMark(mSocket, mUID);
}
MakeSocketBlocking(mSocket, false);
@@ -297,8 +298,8 @@
mState = DISCONNECTED;
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -315,8 +316,8 @@
void ARTSPConnection::performDisconnect() {
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -389,8 +390,8 @@
mState = DISCONNECTED;
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index debd07e..d1767d3 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -1,5 +1,5 @@
-cc_library_static {
- name: "libstagefright_rtsp",
+cc_defaults {
+ name: "libstagefright_rtsp_defaults",
srcs: [
"AAMRAssembler.cpp",
@@ -52,6 +52,21 @@
},
}
+cc_library_static {
+ name: "libstagefright_rtsp",
+
+ srcs: ["NetworkUtils.cpp"],
+ header_libs: ["libnetd_client_headers"],
+ defaults: ["libstagefright_rtsp_defaults"],
+}
+
+cc_library_static {
+ name: "libstagefright_rtsp_player2",
+
+ srcs: ["NetworkUtilsForAppProc.cpp"],
+ defaults: ["libstagefright_rtsp_defaults"],
+}
+
//###############################################################################
cc_test {
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index d183516..5d993db 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -31,6 +31,7 @@
#include "ARTPConnection.h"
#include "ARTSPConnection.h"
#include "ASessionDescription.h"
+#include "NetworkUtils.h"
#include <ctype.h>
#include <cutils/properties.h>
@@ -757,10 +758,10 @@
if (!track->mUsingInterleavedTCP) {
// Clear the tag
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
- HTTPBase::UnRegisterSocketUserMark(track->mRTPSocket);
- HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
- HTTPBase::UnRegisterSocketUserMark(track->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(track->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(track->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(track->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(track->mRTCPSocket);
}
close(track->mRTPSocket);
@@ -886,10 +887,10 @@
// Clear the tag
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
- HTTPBase::UnRegisterSocketUserMark(info->mRTPSocket);
- HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
- HTTPBase::UnRegisterSocketUserMark(info->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(info->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(info->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(info->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(info->mRTCPSocket);
}
close(info->mRTPSocket);
@@ -1665,12 +1666,12 @@
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
if (mUIDValid) {
- HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
- (uint32_t)*(uint32_t*) "RTP_");
- HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
- (uint32_t)*(uint32_t*) "RTP_");
- HTTPBase::RegisterSocketUserMark(info->mRTPSocket, mUID);
- HTTPBase::RegisterSocketUserMark(info->mRTCPSocket, mUID);
+ NetworkUtils::RegisterSocketUserTag(info->mRTPSocket, mUID,
+ (uint32_t)*(uint32_t*) "RTP_");
+ NetworkUtils::RegisterSocketUserTag(info->mRTCPSocket, mUID,
+ (uint32_t)*(uint32_t*) "RTP_");
+ NetworkUtils::RegisterSocketUserMark(info->mRTPSocket, mUID);
+ NetworkUtils::RegisterSocketUserMark(info->mRTCPSocket, mUID);
}
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/media/libstagefright/rtsp/NetworkUtils.cpp b/media/libstagefright/rtsp/NetworkUtils.cpp
new file mode 100644
index 0000000..cc36b78
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+#include <cutils/qtaguid.h>
+#include <NetdClient.h>
+
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
+ int res = qtaguid_tagSocket(sockfd, kTag, uid);
+ if (res != 0) {
+ ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
+ }
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int sockfd) {
+ int res = qtaguid_untagSocket(sockfd);
+ if (res != 0) {
+ ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
+ }
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int sockfd, uid_t uid) {
+ setNetworkForUser(uid, sockfd);
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int sockfd) {
+ RegisterSocketUserMark(sockfd, geteuid());
+}
+
+} // namespace android
diff --git a/media/libstagefright/rtsp/NetworkUtils.h b/media/libstagefright/rtsp/NetworkUtils.h
new file mode 100644
index 0000000..e25ee46
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.h
@@ -0,0 +1,32 @@
+/*
+ * 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 NETWORK_UTILS_H_
+#define NETWORK_UTILS_H_
+
+namespace android {
+
+struct NetworkUtils {
+ static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
+ static void UnRegisterSocketUserTag(int sockfd);
+
+ static void RegisterSocketUserMark(int sockfd, uid_t uid);
+ static void UnRegisterSocketUserMark(int sockfd);
+};
+
+} // namespace android
+
+#endif // NETWORK_UTILS_H_
diff --git a/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
new file mode 100644
index 0000000..662159c
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+
+// NetworkUtils implementation for application process.
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int, uid_t, uint32_t) {
+ // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int) {
+ // No op.
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int, uid_t) {
+ // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int) {
+ // No op.
+}
+
+} // namespace android
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/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 47b0780..1adecb9 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -68,6 +68,7 @@
case AIMAGE_FORMAT_RAW12:
case AIMAGE_FORMAT_DEPTH16:
case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+ case AIMAGE_FORMAT_Y8:
return true;
case AIMAGE_FORMAT_PRIVATE:
// For private format, cpu usage is prohibited.
@@ -94,6 +95,7 @@
case AIMAGE_FORMAT_RAW12:
case AIMAGE_FORMAT_DEPTH16:
case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+ case AIMAGE_FORMAT_Y8:
return 1;
case AIMAGE_FORMAT_PRIVATE:
return 0;
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index a9b54a8..d9ddfd9 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -170,9 +170,7 @@
};
// 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;
+// provided (this native handle MUST have been obtained by AImageReader_getWindowNativeHandle()).
sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(const native_handle_t *handle);
#endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 22fbb42..6537ad1 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -276,6 +276,7 @@
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_BITS_PER_SAMPLE = "bits-per-sample";
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";
@@ -287,10 +288,13 @@
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_CRYPTO_KEY = "crypto-key";
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_CSD_AVC = "csd-avc";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_HEVC = "csd-hevc";
EXPORT const char* AMEDIAFORMAT_KEY_DATE = "date";
EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
@@ -330,11 +334,14 @@
EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
EXPORT const char* AMEDIAFORMAT_KEY_ROTATION = "rotation-degrees";
EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_SAR_HEIGHT = "sar-height";
+EXPORT const char* AMEDIAFORMAT_KEY_SAR_WIDTH = "sar-width";
EXPORT const char* AMEDIAFORMAT_KEY_SEI = "sei";
EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height";
EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
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";
@@ -344,7 +351,6 @@
EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
EXPORT const char* AMEDIAFORMAT_KEY_YEAR = "year";
-
} // extern "C"
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index f936118..15b340c 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -499,7 +499,34 @@
* <p>When an {@link AImage} of this format is obtained from an {@link AImageReader} or
* {@link AImage_getNumberOfPlanes()} method will return zero.</p>
*/
- AIMAGE_FORMAT_PRIVATE = 0x22
+ AIMAGE_FORMAT_PRIVATE = 0x22,
+
+ /**
+ * Android Y8 format.
+ *
+ * <p>Y8 is a planar format comprised of a WxH Y plane only, with each pixel
+ * being represented by 8 bits.</p>
+ *
+ * <p>This format assumes
+ * <ul>
+ * <li>an even width</li>
+ * <li>an even height</li>
+ * <li>a horizontal stride multiple of 16 pixels</li>
+ * </ul>
+ * </p>
+ *
+ * <pre> size = stride * height </pre>
+ *
+ * <p>For example, the {@link AImage} object can provide data
+ * in this format from a {@link ACameraDevice} (if supported) through a
+ * {@link AImageReader} object. The number of planes returned by
+ * {@link AImage_getNumberOfPlanes} will always be 1. The pixel stride returned by
+ * {@link AImage_getPlanePixelStride} will always be 1, and the
+ * {@link AImage_getPlaneRowStride} described the vertical neighboring pixel distance
+ * (in bytes) between adjacent rows.</p>
+ *
+ */
+ AIMAGE_FORMAT_Y8 = 0x20203859
};
/**
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 3fc28f3..3a3268c 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -181,16 +181,27 @@
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_BITS_PER_SAMPLE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_RANGE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_STANDARD __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER __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_CRYPTO_KEY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CSD_AVC __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CSD_HEVC __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_HDR_STATIC_INFO __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_SAR_HEIGHT __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_SAR_WIDTH __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bf4802d..d3bdbae 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -166,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/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 1ce48a9..6ab6369 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -309,8 +309,8 @@
// input and output effect buffers without an intermediary effect process.
// TODO: consider implementing channel conversion.
const size_t safeInputOutputSampleCount =
- inChannelCount != outChannelCount ? 0
- : outChannelCount * std::min(
+ mInChannelCountRequested != mOutChannelCountRequested ? 0
+ : mOutChannelCountRequested * std::min(
mConfig.inputCfg.buffer.frameCount,
mConfig.outputCfg.buffer.frameCount);
const auto accumulateInputToOutput = [this, safeInputOutputSampleCount]() {
@@ -480,7 +480,12 @@
// accumulate input onto output
sp<EffectChain> chain = mChain.promote();
if (chain.get() != nullptr && chain->activeTrackCnt() != 0) {
- accumulateInputToOutput();
+ // similar handling with data_bypass above.
+ if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ accumulateInputToOutput();
+ } else { // EFFECT_BUFFER_ACCESS_WRITE
+ copyInputToOutput();
+ }
}
}
}
diff --git a/services/audiopolicy/config/msd_audio_policy_configuration.xml b/services/audiopolicy/config/msd_audio_policy_configuration.xml
index a84117e..a811f5e 100644
--- a/services/audiopolicy/config/msd_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/msd_audio_policy_configuration.xml
@@ -36,7 +36,8 @@
samplingRates="32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
</mixPort>
- <mixPort name="ms12 output" role="sink">
+ <!-- The HW AV Sync flag is not required, but is recommended -->
+ <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
<profile name="" format="AUDIO_FORMAT_AC3"
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index ab4971d..c9c216b 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1446,6 +1446,7 @@
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
int takePictureCounter;
+ bool shouldSyncWithDevice = true;
{
SharedParameters::Lock l(mParameters);
switch (l.mParameters.state) {
@@ -1531,12 +1532,23 @@
__FUNCTION__, mCameraId);
mZslProcessor->clearZslQueue();
}
+
+ // We should always sync with the device in case flash is turned on,
+ // the camera device suggests that flash is needed (AE state FLASH_REQUIRED)
+ // or we are in some other AE state different from CONVERGED that may need
+ // precapture trigger.
+ if (l.mParameters.flashMode != Parameters::FLASH_MODE_ON &&
+ (l.mParameters.aeState == ANDROID_CONTROL_AE_STATE_CONVERGED)) {
+ shouldSyncWithDevice = false;
+ }
}
ATRACE_ASYNC_BEGIN(kTakepictureLabel, takePictureCounter);
- // Need HAL to have correct settings before (possibly) triggering precapture
- syncWithDevice();
+ // Make sure HAL has correct settings in case precapture trigger is needed.
+ if (shouldSyncWithDevice) {
+ syncWithDevice();
+ }
res = mCaptureSequencer->startCapture();
if (res != OK) {
@@ -1905,6 +1917,11 @@
void Camera2Client::notifyAutoExposure(uint8_t newState, int triggerId) {
ALOGV("%s: Autoexposure state now %d, last trigger %d",
__FUNCTION__, newState, triggerId);
+ {
+ SharedParameters::Lock l(mParameters);
+ // Update state
+ l.mParameters.aeState = newState;
+ }
mCaptureSequencer->notifyAutoExposure(newState, triggerId);
}
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8311a9b..18addb5 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -766,6 +766,7 @@
focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
shadowFocusMode = FOCUS_MODE_INVALID;
+ aeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
camera_metadata_ro_entry_t max3aRegions = staticInfo(ANDROID_CONTROL_MAX_REGIONS,
Parameters::NUM_REGION, Parameters::NUM_REGION);
if (max3aRegions.count != Parameters::NUM_REGION) return NO_INIT;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 9ef3f33..3a709c9 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -122,6 +122,7 @@
int32_t high;
};
+ uint8_t aeState; //latest AE state from Hal
int32_t exposureCompensation;
bool autoExposureLock;
bool autoExposureLockAvailable;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 8bc208d..6d08842 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -83,8 +83,8 @@
// from input, and attached to the outputs. In this case, the input queue's
// dequeueBuffer can still allocate 1 extra buffer before being blocked by
// the output's attachBuffer().
- mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
- mMaxConsumerBuffers+1);
+ mMaxConsumerBuffers++;
+ mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage, mMaxConsumerBuffers);
if (mBufferItemConsumer == nullptr) {
return NO_MEMORY;
}
@@ -108,6 +108,7 @@
mHeight = height;
mFormat = format;
mProducerUsage = producerUsage;
+ mAcquiredInputBuffers = 0;
SP_LOGV("%s: connected", __FUNCTION__);
return res;
@@ -147,6 +148,7 @@
mMaxHalBuffers = 0;
mMaxConsumerBuffers = 0;
+ mAcquiredInputBuffers = 0;
SP_LOGV("%s: Disconnected", __FUNCTION__);
}
@@ -165,7 +167,9 @@
return res;
}
- res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+ if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
+ res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+ }
return res;
}
@@ -266,10 +270,12 @@
return res;
}
- res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
- if (res != OK) {
- SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
- return res;
+ if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
+ res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+ if (res != OK) {
+ SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
+ return res;
+ }
}
return res;
@@ -497,6 +503,7 @@
return;
}
+ mAcquiredInputBuffers++;
SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
@@ -599,6 +606,12 @@
} else {
SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
}
+ } else {
+ if (mAcquiredInputBuffers == 0) {
+ ALOGW("%s: Acquired input buffer count already at zero!", __FUNCTION__);
+ } else {
+ mAcquiredInputBuffers--;
+ }
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index fea1bdb..1eaf2bd 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -269,6 +269,9 @@
// Latest onFrameAvailable return value
std::atomic<status_t> mOnFrameAvailableRes{0};
+ // Currently acquired input buffers
+ size_t mAcquiredInputBuffers;
+
String8 mConsumerName;
};
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
index a2bb469..aee890d 100644
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -71,10 +71,10 @@
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;
- ZipString name(libPathInApk + "/libmedia_codecserviceregistrant.so");
- ret = FindEntry(zipHandle, name, &entry);
+ ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
if (ret == 0) {
android_namespace_t *codecNs = android_create_namespace("codecs",
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/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)
{