IMediaSource: use shared memory to transfer large buffer.
Also move MediaBufferGroup to libstagefright/foundation/.
Bug: 26295488
Change-Id: I88f4e6bf83ffb2b196628a2d4d83ea7b1f6ad9c2
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
index 1420120..f7586a7 100644
--- a/include/media/IMediaSource.h
+++ b/include/media/IMediaSource.h
@@ -26,6 +26,7 @@
struct MediaSource;
class MetaData;
class MediaBuffer;
+class MediaBufferGroup;
class IMediaSource : public IInterface {
public:
@@ -112,6 +113,8 @@
class BnMediaSource: public BnInterface<IMediaSource>
{
public:
+ BnMediaSource();
+
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags = 0);
@@ -122,6 +125,12 @@
virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
return ERROR_UNSUPPORTED;
}
+
+protected:
+ virtual ~BnMediaSource();
+
+private:
+ MediaBufferGroup *mGroup;
};
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 1e0c7d4..18b80e3 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -48,6 +48,9 @@
class MediaBuffer : public MediaBufferBase {
public:
+ // allocations larger than or equal to this will use shared memory.
+ static const size_t kSharedMemThreshold = 64 * 1024;
+
// The underlying data remains the responsibility of the caller!
MediaBuffer(void *data, size_t size);
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index a006f7f..7ca3fa1 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -39,7 +39,11 @@
// The returned buffer will have a reference count of 1.
// If nonBlocking is true and a buffer is not immediately available,
// buffer is set to NULL and it returns WOULD_BLOCK.
- status_t acquire_buffer(MediaBuffer **buffer, bool nonBlocking = false);
+ // If requestedSize is 0, any free MediaBuffer will be returned.
+ // If requestedSize is > 0, the returned MediaBuffer should have buffer
+ // size of at least requstedSize.
+ status_t acquire_buffer(
+ MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
protected:
virtual void signalBufferReturned(MediaBuffer *buffer);
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());
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index fd4ed58..68e02e7 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -29,7 +29,6 @@
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaAdapter.cpp \
- MediaBufferGroup.cpp \
MediaClock.cpp \
MediaCodec.cpp \
MediaCodecList.cpp \
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
deleted file mode 100644
index 6ac6d4a..0000000
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaBufferGroup"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-
-namespace android {
-
-MediaBufferGroup::MediaBufferGroup()
- : mFirstBuffer(NULL),
- mLastBuffer(NULL) {
-}
-
-MediaBufferGroup::~MediaBufferGroup() {
- MediaBuffer *next;
- for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
- buffer = next) {
- next = buffer->nextBuffer();
-
- CHECK_EQ(buffer->refcount(), 0);
-
- buffer->setObserver(NULL);
- buffer->release();
- }
-}
-
-void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- buffer->setObserver(this);
-
- if (mLastBuffer) {
- mLastBuffer->setNextBuffer(buffer);
- } else {
- mFirstBuffer = buffer;
- }
-
- mLastBuffer = buffer;
-}
-
-status_t MediaBufferGroup::acquire_buffer(
- MediaBuffer **out, bool nonBlocking) {
- Mutex::Autolock autoLock(mLock);
-
- for (;;) {
- for (MediaBuffer *buffer = mFirstBuffer;
- buffer != NULL; buffer = buffer->nextBuffer()) {
- if (buffer->refcount() == 0) {
- buffer->add_ref();
- buffer->reset();
-
- *out = buffer;
- goto exit;
- }
- }
-
- if (nonBlocking) {
- *out = NULL;
- return WOULD_BLOCK;
- }
-
- // All buffers are in use. Block until one of them is returned to us.
- mCondition.wait(mLock);
- }
-
-exit:
- return OK;
-}
-
-void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
- Mutex::Autolock autoLock(mLock);
- mCondition.signal();
-}
-
-} // namespace android
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index e17534f..711601f 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -16,6 +16,7 @@
AStringUtils.cpp \
AWakeLock.cpp \
MediaBuffer.cpp \
+ MediaBufferGroup.cpp \
MetaData.cpp \
ParsedMessage.cpp \
base64.cpp \
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index d83a351..fa8e241 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,9 +30,6 @@
namespace android {
-// allocations larger than this will use shared memory
-static const size_t kSharedMemThreshold = 64 * 1024;
-
MediaBuffer::MediaBuffer(void *data, size_t size)
: mObserver(NULL),
mNextBuffer(NULL),
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
new file mode 100644
index 0000000..9022324
--- /dev/null
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+ : mFirstBuffer(NULL),
+ mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+ MediaBuffer *next;
+ for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+ buffer = next) {
+ next = buffer->nextBuffer();
+
+ CHECK_EQ(buffer->refcount(), 0);
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ buffer->setObserver(this);
+
+ if (mLastBuffer) {
+ mLastBuffer->setNextBuffer(buffer);
+ } else {
+ mFirstBuffer = buffer;
+ }
+
+ mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(
+ MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (;;) {
+ MediaBuffer *freeBuffer = NULL;
+ MediaBuffer *freeBufferPrevious = NULL;
+ MediaBuffer *buffer = NULL;
+ MediaBuffer *bufferPrevious = NULL;
+ size_t smallest = requestedSize;
+ for (buffer = mFirstBuffer;
+ buffer != NULL; buffer = buffer->nextBuffer()) {
+ if (buffer->refcount() == 0) {
+ if (buffer->size() >= requestedSize) {
+ break;
+ } else if (buffer->size() < smallest) {
+ freeBuffer = buffer;
+ freeBufferPrevious = bufferPrevious;
+ }
+ }
+ bufferPrevious = buffer;
+ }
+
+ if (buffer == NULL && freeBuffer != NULL) {
+ ALOGV("allocate new buffer, requested size %zu vs available %zu",
+ requestedSize, freeBuffer->size());
+ size_t allocateSize = requestedSize;
+ if (requestedSize < SIZE_MAX / 3) {
+ allocateSize = requestedSize * 3 / 2;
+ }
+ MediaBuffer *newBuffer = new MediaBuffer(allocateSize);
+ newBuffer->setObserver(this);
+ if (freeBuffer == mFirstBuffer) {
+ mFirstBuffer = newBuffer;
+ }
+ if (freeBuffer == mLastBuffer) {
+ mLastBuffer = newBuffer;
+ }
+ newBuffer->setNextBuffer(freeBuffer->nextBuffer());
+ if (freeBufferPrevious != NULL) {
+ freeBufferPrevious->setNextBuffer(newBuffer);
+ }
+ freeBuffer->setObserver(NULL);
+ freeBuffer->release();
+
+ buffer = newBuffer;
+ }
+
+ if (buffer != NULL) {
+ buffer->add_ref();
+ buffer->reset();
+
+ *out = buffer;
+ goto exit;
+ }
+
+ if (nonBlocking) {
+ *out = NULL;
+ return WOULD_BLOCK;
+ }
+
+ // All buffers are in use. Block until one of them is returned to us.
+ mCondition.wait(mLock);
+ }
+
+exit:
+ return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+ Mutex::Autolock autoLock(mLock);
+ mCondition.signal();
+}
+
+} // namespace android