Merge "Fix android.media.cts.ImageReaderDecoderTest fail on MT6580 project" into qt-aml-media-dev
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index d6f1412..68db233 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -33,7 +33,9 @@
dev->unlockDevice();
}
// Fire onClosed callback
- (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+ if (mUserSessionCallback.onClosed != nullptr) {
+ (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+ }
ALOGV("~ACameraCaptureSession: %p is deleted", this);
}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index d24cb81..46a8dae 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -29,7 +29,7 @@
#include "ACameraCaptureSession.inc"
ACameraDevice::~ACameraDevice() {
- mDevice->stopLooper();
+ mDevice->stopLooperAndDisconnect();
}
namespace android {
@@ -112,19 +112,7 @@
}
}
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
- sp<ACameraCaptureSession> session = mCurrentSession.promote();
- {
- Mutex::Autolock _l(mDeviceLock);
- if (!isClosed()) {
- disconnectLocked(session);
- }
- LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
- "CameraDevice looper should've been stopped before ~CameraDevice");
- mCurrentSession = nullptr;
- }
-}
+CameraDevice::~CameraDevice() { }
void
CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -892,8 +880,14 @@
return;
}
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
Mutex::Autolock _l(mDeviceLock);
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
+
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 7a35bf0..6c2ceb3 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -40,6 +40,7 @@
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraCaptureSession.h>
+
#include "ACameraMetadata.h"
namespace android {
@@ -110,7 +111,7 @@
inline ACameraDevice* getWrapper() const { return mWrapper; };
// Stop the looper thread and unregister the handler
- void stopLooper();
+ void stopLooperAndDisconnect();
private:
friend ACameraCaptureSession;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 35c8355..e511a3f 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -45,7 +45,7 @@
using namespace android;
ACameraDevice::~ACameraDevice() {
- mDevice->stopLooper();
+ mDevice->stopLooperAndDisconnect();
}
namespace android {
@@ -125,19 +125,7 @@
}
}
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
- sp<ACameraCaptureSession> session = mCurrentSession.promote();
- {
- Mutex::Autolock _l(mDeviceLock);
- if (!isClosed()) {
- disconnectLocked(session);
- }
- mCurrentSession = nullptr;
- LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
- "CameraDevice looper should've been stopped before ~CameraDevice");
- }
-}
+CameraDevice::~CameraDevice() { }
void
CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -1388,6 +1376,7 @@
// before cbh goes out of scope and causing we call the session
// destructor while holding device lock
cbh.mSession.clear();
+
postSessionMsgAndCleanup(msg);
}
@@ -1400,8 +1389,13 @@
}
}
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
Mutex::Autolock _l(mDeviceLock);
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 9e034c4..7fc699e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -36,6 +36,7 @@
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraCaptureSession.h>
+
#include "ACameraMetadata.h"
#include "utils.h"
@@ -134,7 +135,7 @@
inline ACameraDevice* getWrapper() const { return mWrapper; };
// Stop the looper thread and unregister the handler
- void stopLooper();
+ void stopLooperAndDisconnect();
private:
friend ACameraCaptureSession;
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 7ab0124..938b5f5 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -253,21 +253,9 @@
return true;
}
- static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
-
- static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
-
- static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
- static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
- static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
private:
- ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
- onDeviceError};
- ACameraCaptureSession_stateCallbacks mSessionCb{
- this, onSessionClosed, onSessionReady, onSessionActive};
+ ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
+ ACameraCaptureSession_stateCallbacks mSessionCb{ this, nullptr, nullptr, nullptr};
native_handle_t* mImgReaderAnw = nullptr; // not owned by us.
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d74bc53..71bb218 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -797,37 +797,55 @@
}
Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
- if (ssRelease.opaqueData.size() == 0) {
+ // OpaqueData starts with 4 byte decimal integer string
+ const size_t kFourBytesOffset = 4;
+ if (ssRelease.opaqueData.size() < kFourBytesOffset) {
+ ALOGE("Invalid secureStopRelease length");
return Status::BAD_VALUE;
}
Status status = Status::OK;
std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
+ if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
+ // The minimum size of SecureStopRelease has to contain
+ // a 4 bytes count and one secureStop id
+ ALOGE("Total size of secureStops is too short");
+ return Status::BAD_VALUE;
+ }
+
// The format of opaqueData is shared between the server
// and the drm service. The clearkey implementation consists of:
// count - number of secure stops
// list of fixed length secure stops
- size_t countBufferSize = sizeof(uint32_t);
uint32_t count = 0;
sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
// Avoid divide by 0 below.
if (count == 0) {
+ ALOGE("Invalid 0 secureStop count");
return Status::BAD_VALUE;
}
- size_t secureStopSize = (input.size() - countBufferSize) / count;
- uint8_t buffer[secureStopSize];
- size_t offset = countBufferSize; // skip the count
+ // Computes the fixed length secureStop size
+ size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
+ if (secureStopSize < kSecureStopIdSize) {
+ // A valid secureStop contains the id plus data
+ ALOGE("Invalid secureStop size");
+ return Status::BAD_VALUE;
+ }
+ uint8_t* buffer = new uint8_t[secureStopSize];
+ size_t offset = kFourBytesOffset; // skip the count
for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
memcpy(buffer, input.data() + offset, secureStopSize);
- std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+ // A secureStop contains id+data, we only use the id for removal
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
status = removeSecureStop(toHidlVec(id));
if (Status::OK != status) break;
}
+ delete[] buffer;
return status;
}
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 8c8e6d1..0773387 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -700,8 +700,8 @@
}
private:
- uint32_t mWidth;
- uint32_t mHeight;
+ int32_t mWidth;
+ int32_t mHeight;
};
status_t IspeBox::parse(off64_t offset, size_t size) {
@@ -715,12 +715,19 @@
if (size < 8) {
return ERROR_MALFORMED;
}
- if (!source()->getUInt32(offset, &mWidth)
- || !source()->getUInt32(offset + 4, &mHeight)) {
+ if (!source()->getUInt32(offset, (uint32_t *)&mWidth)
+ || !source()->getUInt32(offset + 4, (uint32_t *)&mHeight)) {
return ERROR_IO;
}
- ALOGV("property ispe: %dx%d", mWidth, mHeight);
+ // Validate that the dimension doesn't cause overflow on calculated max input size.
+ // Max input size is width*height*1.5, restrict width*height to 1<<29 so that
+ // we don't need to cast to int64_t when doing mults.
+ if (mWidth <= 0 || mHeight <= 0 || mWidth > (1 << 29) / mHeight) {
+ return ERROR_MALFORMED;
+ }
+
+ ALOGV("property ispe: %dx%d", mWidth, mHeight);
return OK;
}
@@ -1524,8 +1531,9 @@
default: break; // don't set if invalid
}
}
+ // we validated no overflow in IspeBox::parse()
AMediaFormat_setInt32(meta,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+ AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
if (!image->thumbnails.empty()) {
ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
@@ -1561,8 +1569,9 @@
AMEDIAFORMAT_KEY_TILE_WIDTH, image->width);
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_TILE_HEIGHT, image->height);
+ // we validated no overflow in IspeBox::parse()
AMediaFormat_setInt32(meta,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+ AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
}
if (image->hvcc == NULL) {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 12982ed..86ed610 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1561,8 +1561,12 @@
{
*offset += chunk_size;
- if (mLastTrack == NULL)
+ // the absolute minimum size of a compliant mett box is 11 bytes:
+ // 6 byte reserved, 2 byte index, null byte, one char mime_format, null byte
+ // The resulting mime_format would be invalid at that size though.
+ if (mLastTrack == NULL || chunk_data_size < 11) {
return ERROR_MALFORMED;
+ }
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
if (buffer.get() == NULL) {
@@ -1574,10 +1578,24 @@
return ERROR_IO;
}
+ // ISO-14496-12:
+ // int8 reserved[6]; // should be all zeroes
+ // int16_t data_reference_index;
+ // char content_encoding[]; // null terminated, optional (= just the null byte)
+ // char mime_format[]; // null terminated, mandatory
+ // optional other boxes
+ //
+ // API < 29:
+ // char mime_format[]; // null terminated
+ //
+ // API >= 29
+ // char mime_format[]; // null terminated
+ // char mime_format[]; // null terminated
+
// Prior to API 29, the metadata track was not compliant with ISO/IEC
// 14496-12-2015. This led to some ISO-compliant parsers failing to read the
// metatrack. As of API 29 and onwards, a change was made to metadata track to
- // make it compliant with the standard. The workaround is to write the
+ // make it somewhat compatible with the standard. The workaround is to write the
// null-terminated mime_format string twice. This allows compliant parsers to
// read the missing reserved, data_reference_index, and content_encoding fields
// from the first mime_type string. The actual mime_format field would then be
@@ -1586,27 +1604,27 @@
// as it would only read the first null-terminated mime_format string. To enable
// reading metadata tracks generated from both the non-compliant and compliant
// formats, a check needs to be done to see which format is used.
- int null_pos = 0;
- const unsigned char *str = buffer.get();
- while (null_pos < chunk_data_size) {
- if (*(str + null_pos) == '\0') {
- break;
- }
- ++null_pos;
- }
+ const char *str = (const char*) buffer.get();
+ size_t string_length = strnlen(str, chunk_data_size);
- if (null_pos == chunk_data_size - 1) {
- // This is not a standard ompliant metadata track.
- String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
- AMediaFormat_setString(mLastTrack->meta,
- AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+ if (string_length == chunk_data_size - 1) {
+ // This is likely a pre API 29 file, since it's a single null terminated
+ // string filling the entire box.
+ AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, str);
} else {
- // This is a standard compliant metadata track.
- String8 contentEncoding((const char *)(buffer.get() + 8));
- String8 mimeFormat((const char *)(buffer.get() + 8 + contentEncoding.size() + 1),
- chunk_data_size - 8 - contentEncoding.size() - 1);
- AMediaFormat_setString(mLastTrack->meta,
- AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+ // This might be a fully compliant metadata track, a "double mime" compatibility
+ // track, or anything else, including a single non-terminated string, so we need
+ // to determine the length of each string we want to parse out of the box.
+ size_t encoding_length = strnlen(str + 8, chunk_data_size - 8);
+ if (encoding_length + 8 >= chunk_data_size - 2) {
+ // the encoding extends to the end of the box, so there's no mime_format
+ return ERROR_MALFORMED;
+ }
+ String8 contentEncoding(str + 8, encoding_length);
+ String8 mimeFormat(str + 8 + encoding_length + 1,
+ chunk_data_size - 8 - encoding_length - 1);
+ AMediaFormat_setString(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
}
break;
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 9b77223..f5c97d8 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -473,7 +473,7 @@
void AudioStream::MyPlayerBase::registerWithAudioManager() {
if (!mRegistered) {
- init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+ init(android::PLAYER_TYPE_AAUDIO, AAudioConvert_usageToInternal(mParent->getUsage()));
mRegistered = true;
}
}
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index dd95e34..efa0512 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -1339,10 +1339,14 @@
}
case GET_EFFECT_DESCRIPTOR: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- effect_uuid_t uuid;
- data.read(&uuid, sizeof(effect_uuid_t));
- effect_uuid_t type;
- data.read(&type, sizeof(effect_uuid_t));
+ effect_uuid_t uuid = {};
+ if (data.read(&uuid, sizeof(effect_uuid_t)) != NO_ERROR) {
+ android_errorWriteLog(0x534e4554, "139417189");
+ }
+ effect_uuid_t type = {};
+ if (data.read(&type, sizeof(effect_uuid_t)) != NO_ERROR) {
+ android_errorWriteLog(0x534e4554, "139417189");
+ }
uint32_t preferredTypeFlag = data.readUint32();
effect_descriptor_t desc = {};
status_t status = getEffectDescriptor(&uuid, &type, preferredTypeFlag, &desc);
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index afdcd37..f21d2b3 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -130,29 +130,32 @@
} else if (n < 0) {
break;
} else {
- if (buffer[0] == 0x00) {
+ if (buffer[0] == 0x00) { // OK to access buffer[0] since n must be > 0 here
// XXX legacy
if (extra == NULL) {
extra = new AMessage;
}
- uint8_t type = buffer[1];
+ uint8_t type = 0;
+ if (n > 1) {
+ type = buffer[1];
- if (type & 2) {
- int64_t mediaTimeUs;
- memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
+ if ((type & 2) && (n >= 2 + sizeof(int64_t))) {
+ int64_t mediaTimeUs;
+ memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
- extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+ extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+ }
}
mTSParser->signalDiscontinuity(
((type & 1) == 0)
- ? ATSParser::DISCONTINUITY_TIME
- : ATSParser::DISCONTINUITY_FORMATCHANGE,
+ ? ATSParser::DISCONTINUITY_TIME
+ : ATSParser::DISCONTINUITY_FORMATCHANGE,
extra);
} else {
- status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
+ status_t err = mTSParser->feedTSPacket(buffer, n);
if (err != OK) {
ALOGE("TS Parser returned error %d", err);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index acb8b3c..e1d35e8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -54,9 +54,8 @@
mState = STATE_ERROR;
}
- if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
- mBufferReleasedListener = new BufferReleasedListener(this);
- }
+ bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+ mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
}
Camera3OutputStream::Camera3OutputStream(int id,
@@ -87,9 +86,8 @@
mState = STATE_ERROR;
}
- if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
- mBufferReleasedListener = new BufferReleasedListener(this);
- }
+ bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+ mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
}
Camera3OutputStream::Camera3OutputStream(int id,
@@ -124,10 +122,8 @@
}
mConsumerName = String8("Deferred");
- if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
- mBufferReleasedListener = new BufferReleasedListener(this);
- }
-
+ bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+ mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
}
Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
@@ -151,9 +147,8 @@
mDropBuffers(false),
mDequeueBufferLatency(kDequeueLatencyBinSize) {
- if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
- mBufferReleasedListener = new BufferReleasedListener(this);
- }
+ bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+ mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
// Subclasses expected to initialize mConsumer themselves
}
@@ -261,7 +256,7 @@
notifyBufferReleased(anwBuffer);
if (mUseBufferManager) {
// Return this buffer back to buffer manager.
- mBufferReleasedListener->onBufferReleased();
+ mBufferProducerListener->onBufferReleased();
}
} else {
if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
@@ -387,8 +382,8 @@
// Configure consumer-side ANativeWindow interface. The listener may be used
// to notify buffer manager (if it is used) of the returned buffers.
res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA,
- /*listener*/mBufferReleasedListener,
- /*reportBufferRemoval*/true);
+ /*reportBufferRemoval*/true,
+ /*listener*/mBufferProducerListener);
if (res != OK) {
ALOGE("%s: Unable to connect to native window for stream %d",
__FUNCTION__, mId);
@@ -790,7 +785,7 @@
return INVALID_OPERATION;
}
-void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
+void Camera3OutputStream::BufferProducerListener::onBufferReleased() {
sp<Camera3OutputStream> stream = mParent.promote();
if (stream == nullptr) {
ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
@@ -823,6 +818,25 @@
}
}
+void Camera3OutputStream::BufferProducerListener::onBuffersDiscarded(
+ const std::vector<sp<GraphicBuffer>>& buffers) {
+ sp<Camera3OutputStream> stream = mParent.promote();
+ if (stream == nullptr) {
+ ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
+ return;
+ }
+
+ if (buffers.size() > 0) {
+ Mutex::Autolock l(stream->mLock);
+ stream->onBuffersRemovedLocked(buffers);
+ if (stream->mUseBufferManager) {
+ stream->mBufferManager->onBuffersRemoved(stream->getId(),
+ stream->getStreamSetId(), buffers.size());
+ }
+ ALOGV("Stream %d: %zu Buffers discarded.", stream->getId(), buffers.size());
+ }
+}
+
void Camera3OutputStream::onBuffersRemovedLocked(
const std::vector<sp<GraphicBuffer>>& removedBuffers) {
sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 729c655..b4e49f9 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -146,18 +146,22 @@
*/
virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
- class BufferReleasedListener : public BnProducerListener {
+ class BufferProducerListener : public SurfaceListener {
public:
- BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
+ BufferProducerListener(wp<Camera3OutputStream> parent, bool needsReleaseNotify)
+ : mParent(parent), mNeedsReleaseNotify(needsReleaseNotify) {}
- /**
- * Implementation of IProducerListener, used to notify this stream that the consumer
- * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
- */
- virtual void onBufferReleased();
+ /**
+ * Implementation of IProducerListener, used to notify this stream that the consumer
+ * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
+ */
+ virtual void onBufferReleased();
+ virtual bool needsReleaseNotify() { return mNeedsReleaseNotify; }
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers);
private:
- wp<Camera3OutputStream> mParent;
+ wp<Camera3OutputStream> mParent;
+ bool mNeedsReleaseNotify;
};
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
@@ -262,10 +266,10 @@
sp<Camera3BufferManager> mBufferManager;
/**
- * Buffer released listener, used to notify the buffer manager that a buffer is released
- * from consumer side.
+ * Buffer producer listener, used to handle notification when a buffer is released
+ * from consumer side, or a set of buffers are discarded by the consumer.
*/
- sp<BufferReleasedListener> mBufferReleasedListener;
+ sp<BufferProducerListener> mBufferProducerListener;
/**
* Flag indicating if the buffer manager is used to allocate the stream buffers
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index fa5bc4a..765ac99 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -14,6 +14,7 @@
"libbase",
"libcodec2_hidl@1.0",
"libcodec2_vndk",
+ "libhidlbase",
"libutils",
],
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 706ebee..7f7ceca 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -18,21 +18,411 @@
#define LOG_TAG "CodecServiceRegistrant"
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <C2Component.h>
#include <C2PlatformSupport.h>
#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+#include <hidl/HidlSupport.h>
#include <media/CodecServiceRegistrant.h>
+namespace /* unnamed */ {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using namespace ::android::hardware::media::c2::V1_0;
+using namespace ::android::hardware::media::c2::V1_0::utils;
+
+constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
+
+// Converter from IComponentStore to C2ComponentStore.
+class H2C2ComponentStore : public C2ComponentStore {
+protected:
+ sp<IComponentStore> mStore;
+ sp<IConfigurable> mConfigurable;
+public:
+ explicit H2C2ComponentStore(sp<IComponentStore> const& store)
+ : mStore{store},
+ mConfigurable{[store]() -> sp<IConfigurable>{
+ if (!store) {
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> transResult =
+ store->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()} {
+ if (!mConfigurable) {
+ LOG(ERROR) << "Preferred store is corrupted.";
+ }
+ }
+
+ virtual ~H2C2ComponentStore() override = default;
+
+ virtual c2_status_t config_sm(
+ std::vector<C2Param*> const ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ Params hidlParams;
+ if (!createParamsBlob(&hidlParams, params)) {
+ LOG(ERROR) << "config -- bad input.";
+ return C2_TRANSACTION_FAILED;
+ }
+ c2_status_t status{};
+ Return<void> transResult = mConfigurable->config(
+ hidlParams,
+ true,
+ [&status, ¶ms, failures](
+ Status s,
+ const hidl_vec<SettingResult> f,
+ const Params& o) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "config -- call failed: "
+ << status << ".";
+ }
+ size_t i = failures->size();
+ failures->resize(i + f.size());
+ for (const SettingResult& sf : f) {
+ if (!objcpy(&(*failures)[i++], sf)) {
+ LOG(ERROR) << "config -- "
+ << "invalid SettingResult returned.";
+ return;
+ }
+ }
+ if (!updateParamsFromBlob(params, o)) {
+ LOG(ERROR) << "config -- "
+ << "failed to parse returned params.";
+ status = C2_CORRUPTED;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "config -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ };
+
+ virtual c2_status_t copyBuffer(
+ std::shared_ptr<C2GraphicBuffer>,
+ std::shared_ptr<C2GraphicBuffer>) override {
+ LOG(ERROR) << "copyBuffer -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createComponent(
+ C2String, std::shared_ptr<C2Component> *const component) override {
+ component->reset();
+ LOG(ERROR) << "createComponent -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createInterface(
+ C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
+ interface->reset();
+ LOG(ERROR) << "createInterface -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t query_sm(
+ const std::vector<C2Param *> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>> *const heapParams) const
+ override {
+ hidl_vec<ParamIndex> indices(
+ stackParams.size() + heapParamIndices.size());
+ size_t numIndices = 0;
+ for (C2Param* const& stackParam : stackParams) {
+ if (!stackParam) {
+ LOG(WARNING) << "query -- null stack param encountered.";
+ continue;
+ }
+ indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+ }
+ size_t numStackIndices = numIndices;
+ for (const C2Param::Index& index : heapParamIndices) {
+ indices[numIndices++] =
+ static_cast<ParamIndex>(static_cast<uint32_t>(index));
+ }
+ indices.resize(numIndices);
+ if (heapParams) {
+ heapParams->reserve(heapParams->size() + numIndices);
+ }
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->query(
+ indices,
+ true,
+ [&status, &numStackIndices, &stackParams, heapParams](
+ Status s, const Params& p) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "query -- call failed: "
+ << status << ".";
+ return;
+ }
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, p)) {
+ LOG(ERROR) << "query -- error while parsing params.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ size_t i = 0;
+ for (auto it = paramPointers.begin();
+ it != paramPointers.end(); ) {
+ C2Param* paramPointer = *it;
+ if (numStackIndices > 0) {
+ --numStackIndices;
+ if (!paramPointer) {
+ LOG(WARNING) << "query -- null stack param.";
+ ++it;
+ continue;
+ }
+ for (; i < stackParams.size() && !stackParams[i]; ) {
+ ++i;
+ }
+ if (i >= stackParams.size()) {
+ LOG(ERROR) << "query -- unexpected error.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ if (stackParams[i]->index() != paramPointer->index()) {
+ LOG(WARNING) << "query -- param skipped: "
+ "index = "
+ << stackParams[i]->index() << ".";
+ stackParams[i++]->invalidate();
+ continue;
+ }
+ if (!stackParams[i++]->updateFrom(*paramPointer)) {
+ LOG(WARNING) << "query -- param update failed: "
+ "index = "
+ << paramPointer->index() << ".";
+ }
+ } else {
+ if (!paramPointer) {
+ LOG(WARNING) << "query -- null heap param.";
+ ++it;
+ continue;
+ }
+ if (!heapParams) {
+ LOG(WARNING) << "query -- "
+ "unexpected extra stack param.";
+ } else {
+ heapParams->emplace_back(
+ C2Param::Copy(*paramPointer));
+ }
+ }
+ ++it;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "query -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->querySupportedParams(
+ std::numeric_limits<uint32_t>::min(),
+ std::numeric_limits<uint32_t>::max(),
+ [&status, params](
+ Status s,
+ const hidl_vec<ParamDescriptor>& p) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "querySupportedParams -- call failed: "
+ << status << ".";
+ return;
+ }
+ size_t i = params->size();
+ params->resize(i + p.size());
+ for (const ParamDescriptor& sp : p) {
+ if (!objcpy(&(*params)[i++], sp)) {
+ LOG(ERROR) << "querySupportedParams -- "
+ << "invalid returned ParamDescriptor.";
+ return;
+ }
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "querySupportedParams -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual c2_status_t querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery> &fields) const {
+ hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
+ for (size_t i = 0; i < fields.size(); ++i) {
+ if (!objcpy(&inFields[i], fields[i])) {
+ LOG(ERROR) << "querySupportedValues -- bad input";
+ return C2_TRANSACTION_FAILED;
+ }
+ }
+
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->querySupportedValues(
+ inFields,
+ true,
+ [&status, &inFields, &fields](
+ Status s,
+ const hidl_vec<FieldSupportedValuesQueryResult>& r) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "querySupportedValues -- call failed: "
+ << status << ".";
+ return;
+ }
+ if (r.size() != fields.size()) {
+ LOG(ERROR) << "querySupportedValues -- "
+ "input and output lists "
+ "have different sizes.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ for (size_t i = 0; i < fields.size(); ++i) {
+ if (!objcpy(&fields[i], inFields[i], r[i])) {
+ LOG(ERROR) << "querySupportedValues -- "
+ "invalid returned value.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "querySupportedValues -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual C2String getName() const {
+ C2String outName;
+ Return<void> transResult = mConfigurable->getName(
+ [&outName](const hidl_string& name) {
+ outName = name.c_str();
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "getName -- transaction failed.";
+ }
+ return outName;
+ }
+
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const
+ override {
+ struct SimpleParamReflector : public C2ParamReflector {
+ virtual std::unique_ptr<C2StructDescriptor> describe(
+ C2Param::CoreIndex coreIndex) const {
+ hidl_vec<ParamIndex> indices(1);
+ indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
+ std::unique_ptr<C2StructDescriptor> descriptor;
+ Return<void> transResult = mBase->getStructDescriptors(
+ indices,
+ [&descriptor](
+ Status s,
+ const hidl_vec<StructDescriptor>& sd) {
+ c2_status_t status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() failed: "
+ << status << ".";
+ descriptor.reset();
+ return;
+ }
+ if (sd.size() != 1) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() "
+ "returned vector of size "
+ << sd.size() << ". "
+ "It should be 1.";
+ descriptor.reset();
+ return;
+ }
+ if (!objcpy(&descriptor, sd[0])) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() returned "
+ "corrupted data.";
+ descriptor.reset();
+ return;
+ }
+ });
+ return descriptor;
+ }
+
+ explicit SimpleParamReflector(sp<IComponentStore> base)
+ : mBase(base) { }
+
+ sp<IComponentStore> mBase;
+ };
+
+ return std::make_shared<SimpleParamReflector>(mStore);
+ }
+
+ virtual std::vector<std::shared_ptr<const C2Component::Traits>>
+ listComponents() override {
+ LOG(ERROR) << "listComponents -- not supported.";
+ return {};
+ }
+};
+
+bool ionPropertiesDefined() {
+ using namespace ::android::base;
+ std::string heapMask =
+ GetProperty("ro.com.android.media.swcodec.ion.heapmask", "undefined");
+ std::string flags =
+ GetProperty("ro.com.android.media.swcodec.ion.flags", "undefined");
+ std::string align =
+ GetProperty("ro.com.android.media.swcodec.ion.align", "undefined");
+ if (heapMask != "undefined" ||
+ flags != "undefined" ||
+ align != "undefined") {
+ LOG(INFO)
+ << "Some system properties for mediaswcodec ION usage are set: "
+ << "heapmask = " << heapMask << ", "
+ << "flags = " << flags << ", "
+ << "align = " << align << ". "
+ << "Preferred Codec2 store is defaulted to \"software\".";
+ return true;
+ }
+ return false;
+}
+
+} // unnamed namespace
+
extern "C" void RegisterCodecServices() {
- using namespace ::android::hardware::media::c2::V1_0;
+ using ComponentStore = ::android::hardware::media::c2::V1_0::utils::
+ ComponentStore;
LOG(INFO) << "Creating software Codec2 service...";
- android::sp<IComponentStore> store =
- new utils::ComponentStore(
- android::GetCodec2PlatformComponentStore());
+ sp<ComponentStore> store =
+ new ComponentStore(::android::GetCodec2PlatformComponentStore());
if (store == nullptr) {
LOG(ERROR) <<
"Cannot create software Codec2 service.";
} else {
+ if (!ionPropertiesDefined()) {
+ std::string preferredStoreName = "default";
+ sp<IComponentStore> preferredStore =
+ IComponentStore::getService(preferredStoreName.c_str());
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 store is defaulted to \"software\".";
+ }
+ }
if (store->registerAsService("software") != android::OK) {
LOG(ERROR) <<
"Cannot register software Codec2 service.";