Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44333e51 authored by Marco Nelissen's avatar Marco Nelissen Committed by Android (Google) Code Review
Browse files

Merge "MediaSource: use shared memory for transferring larger buffers"

parents 438e7572 b65990f4
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <pthread.h>

#include <binder/MemoryDealer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>

@@ -93,6 +94,8 @@ protected:
private:
    friend class MediaBufferGroup;
    friend class OMXDecoder;
    friend class BnMediaSource;
    friend class BpMediaSource;

    // For use by OMXDecoder, reference count must be 1, drop reference
    // count to 0 without signalling the observer.
@@ -118,6 +121,7 @@ private:

    MediaBuffer(const MediaBuffer &);
    MediaBuffer &operator=(const MediaBuffer &);
    sp<IMemory> mMemory;
};

}  // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#define LOG_NDEBUG 0
//#define LOG_NDEBUG 0
#define LOG_TAG "BpMediaExtractor"
#include <utils/Log.h>

+103 −12
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define LOG_TAG "BpMediaSource"
#include <utils/Log.h>

#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>

@@ -34,9 +35,69 @@ enum {
    STOP,
    PAUSE,
    GETFORMAT,
    READ
    READ,
    RELEASE_BUFFER
};

enum {
    NULL_BUFFER,
    SHARED_BUFFER,
    INLINE_BUFFER
};

class RemoteMediaBufferReleaser : public BBinder {
public:
    RemoteMediaBufferReleaser(MediaBuffer *buf) {
        mBuf = buf;
    }
    ~RemoteMediaBufferReleaser() {
        if (mBuf) {
            ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
            mBuf->release();
        }
    }
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0) {
        if (code == RELEASE_BUFFER) {
            mBuf->release();
            mBuf = NULL;
            return OK;
        } else {
            return BBinder::onTransact(code, data, reply, flags);
        }
    }
private:
    MediaBuffer *mBuf;
};


class RemoteMediaBufferWrapper : public MediaBuffer {
public:
    RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
protected:
    virtual ~RemoteMediaBufferWrapper();
private:
    sp<IMemory> mMemory;
    sp<IBinder> mRemoteSource;
};

RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
: MediaBuffer(mem->pointer(), mem->size()) {
    mMemory = mem;
    mRemoteSource = source;
}

RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
    mMemory.clear();
    // Explicitly ask the remote side to release the buffer. We could also just clear
    // mRemoteSource, but that doesn't immediately release the reference on the remote side.
    Parcel data, reply;
    mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
    mRemoteSource.clear();
}

class BpMediaSource : public BpInterface<IMediaSource> {
public:
    BpMediaSource(const sp<IBinder>& impl)
@@ -94,13 +155,26 @@ public:
            return ret;
        }
        // wrap the returned data in a MediaBuffer
        // XXX use a group, and use shared memory for transfer
        ret = reply.readInt32();
        int32_t len = reply.readInt32();
        if (len < 0) {
            ALOGV("got status %d and len %d, returning NULL buffer", ret, len);
        int32_t buftype = reply.readInt32();
        if (buftype == SHARED_BUFFER) {
            sp<IBinder> remote = reply.readStrongBinder();
            sp<IBinder> binder = reply.readStrongBinder();
            sp<IMemory> mem = interface_cast<IMemory>(binder);
            if (mem == NULL) {
                ALOGE("received NULL IMemory for shared buffer");
            }
            size_t offset = reply.readInt32();
            size_t length = reply.readInt32();
            MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
            buf->set_range(offset, length);
            buf->meta_data()->updateFromParcel(reply);
            *buffer = buf;
        } else if (buftype == NULL_BUFFER) {
            ALOGV("got status %d and NULL buffer", ret);
            *buffer = NULL;
        } else {
            int32_t len = reply.readInt32();
            ALOGV("got status %d and len %d", ret, len);
            *buffer = new MediaBuffer(len);
            reply.read((*buffer)->data(), len);
@@ -183,17 +257,34 @@ status_t BnMediaSource::onTransact(
            } else {
                ret = read(&buf, NULL);
            }
            // return data inside binder for now
            // XXX return data using shared memory

            reply->writeInt32(ret);
            if (buf != NULL) {
                ALOGV("ret %d, buflen %zu", ret, buf->range_length());
                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);
                    reply->writeInt32(SHARED_BUFFER);
                    RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
                    reply->writeStrongBinder(wrapper);
                    reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
                    reply->writeInt32(buf->range_offset());
                    reply->writeInt32(usedSize);
                    buf->meta_data()->writeToParcel(*reply);
                } else {
                    // buffer is not in shared memory, or is small: copy it
                    if (buf->mMemory != NULL) {
                        ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
                    }
                    reply->writeInt32(INLINE_BUFFER);
                    reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
                    buf->meta_data()->writeToParcel(*reply);
                    buf->release();
                }
            } else {
                ALOGV("ret %d, buf %p", ret, buf);
                reply->writeInt32(-1);
                reply->writeInt32(NULL_BUFFER);
            }
            return NO_ERROR;
        }
+21 −2
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@

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),
@@ -47,13 +50,29 @@ MediaBuffer::MediaBuffer(size_t size)
    : mObserver(NULL),
      mNextBuffer(NULL),
      mRefCount(0),
      mData(malloc(size)),
      mData(NULL),
      mSize(size),
      mRangeOffset(0),
      mRangeLength(size),
      mOwnsData(true),
      mMetaData(new MetaData),
      mOriginal(NULL) {
    if (size < kSharedMemThreshold) {
        mData = malloc(size);
    } else {
        sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
        mMemory = memoryDealer->allocate(size);
        if (mMemory == NULL) {
            ALOGW("Failed to allocate shared memory, trying regular allocation!");
            mData = malloc(size);
            if (mData == NULL) {
                ALOGE("Out of memory");
            }
        } else {
            mData = mMemory->pointer();
            ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
        }
    }
}

MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
@@ -158,7 +177,7 @@ void MediaBuffer::reset() {
MediaBuffer::~MediaBuffer() {
    CHECK(mObserver == NULL);

    if (mOwnsData && mData != NULL) {
    if (mOwnsData && mData != NULL && mMemory == NULL) {
        free(mData);
        mData = NULL;
    }