IMediaSource: use shared memory to transfer large buffer.
Also move MediaBufferGroup to libstagefright/foundation/.
Bug: 26295488
Change-Id: I88f4e6bf83ffb2b196628a2d4d83ea7b1f6ad9c2
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index fc9a123..b988c46 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -25,6 +25,7 @@
#include <binder/Parcel.h>
#include <media/IMediaSource.h>
#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
@@ -47,8 +48,9 @@
class RemoteMediaBufferReleaser : public BBinder {
public:
- RemoteMediaBufferReleaser(MediaBuffer *buf) {
+ RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
mBuf = buf;
+ mOwner = owner;
}
~RemoteMediaBufferReleaser() {
if (mBuf) {
@@ -70,6 +72,10 @@
}
private:
MediaBuffer *mBuf;
+ // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
+ // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
+ // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
+ sp<BnMediaSource> mOwner;
};
@@ -207,6 +213,15 @@
#undef LOG_TAG
#define LOG_TAG "BnMediaSource"
+BnMediaSource::BnMediaSource()
+ : mGroup(NULL) {
+}
+
+BnMediaSource::~BnMediaSource() {
+ delete mGroup;
+ mGroup = NULL;
+}
+
status_t BnMediaSource::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -263,17 +278,45 @@
size_t usedSize = buf->range_length();
// even if we're using shared memory, we might not want to use it, since for small
// sizes it's faster to copy data through the Binder transaction
- if (buf->mMemory != NULL && usedSize >= 64 * 1024) {
- ALOGV("buffer is using shared memory: %zu", usedSize);
+ // On the other hand, if the data size is large enough, it's better to use shared
+ // memory. When data is too large, binder can't handle it.
+ if (usedSize >= MediaBuffer::kSharedMemThreshold) {
+ ALOGV("use shared memory: %zu", usedSize);
+
+ MediaBuffer *transferBuf = buf;
+ size_t offset = buf->range_offset();
+ if (transferBuf->mMemory == NULL) {
+ if (mGroup == NULL) {
+ mGroup = new MediaBufferGroup;
+ size_t allocateSize = usedSize;
+ if (usedSize < SIZE_MAX / 3) {
+ allocateSize = usedSize * 3 / 2;
+ }
+ mGroup->add_buffer(new MediaBuffer(allocateSize));
+ }
+
+ ret = mGroup->acquire_buffer(
+ &transferBuf, false /* nonBlocking */, usedSize);
+ if (ret != OK || transferBuf == NULL || transferBuf->mMemory == NULL) {
+ ALOGW("failed to acquire shared memory, ret %d", ret);
+ reply->writeInt32(NULL_BUFFER);
+ return NO_ERROR;
+ }
+ memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
+ buf->range_length());
+ offset = 0;
+ }
+
reply->writeInt32(SHARED_BUFFER);
- RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
+ RemoteMediaBufferReleaser *wrapper =
+ new RemoteMediaBufferReleaser(transferBuf, this);
reply->writeStrongBinder(wrapper);
- reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
- reply->writeInt32(buf->range_offset());
+ reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
+ reply->writeInt32(offset);
reply->writeInt32(usedSize);
buf->meta_data()->writeToParcel(*reply);
} else {
- // buffer is not in shared memory, or is small: copy it
+ // buffer is small: copy it
if (buf->mMemory != NULL) {
ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
}