1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "MediaBuffer"
18#include <utils/Log.h>
19
20#include <errno.h>
21#include <pthread.h>
22#include <stdlib.h>
23
24#include <media/stagefright/foundation/ABuffer.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MetaData.h>
28
29#include <ui/GraphicBuffer.h>
30
31namespace android {
32
33MediaBuffer::MediaBuffer(void *data, size_t size)
34    : mObserver(NULL),
35      mNextBuffer(NULL),
36      mRefCount(0),
37      mData(data),
38      mSize(size),
39      mRangeOffset(0),
40      mRangeLength(size),
41      mOwnsData(false),
42      mMetaData(new MetaData),
43      mOriginal(NULL) {
44}
45
46MediaBuffer::MediaBuffer(size_t size)
47    : mObserver(NULL),
48      mNextBuffer(NULL),
49      mRefCount(0),
50      mData(NULL),
51      mSize(size),
52      mRangeOffset(0),
53      mRangeLength(size),
54      mOwnsData(true),
55      mMetaData(new MetaData),
56      mOriginal(NULL) {
57    if (size < kSharedMemThreshold) {
58        mData = malloc(size);
59    } else {
60        sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
61        mMemory = memoryDealer->allocate(size);
62        if (mMemory == NULL) {
63            ALOGW("Failed to allocate shared memory, trying regular allocation!");
64            mData = malloc(size);
65            if (mData == NULL) {
66                ALOGE("Out of memory");
67            }
68        } else {
69            mData = mMemory->pointer();
70            ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
71        }
72    }
73}
74
75MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
76    : mObserver(NULL),
77      mNextBuffer(NULL),
78      mRefCount(0),
79      mData(NULL),
80      mSize(1),
81      mRangeOffset(0),
82      mRangeLength(mSize),
83      mGraphicBuffer(graphicBuffer),
84      mOwnsData(false),
85      mMetaData(new MetaData),
86      mOriginal(NULL) {
87}
88
89MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
90    : mObserver(NULL),
91      mNextBuffer(NULL),
92      mRefCount(0),
93      mData(buffer->data()),
94      mSize(buffer->size()),
95      mRangeOffset(0),
96      mRangeLength(mSize),
97      mBuffer(buffer),
98      mOwnsData(false),
99      mMetaData(new MetaData),
100      mOriginal(NULL) {
101}
102
103void MediaBuffer::release() {
104    if (mObserver == NULL) {
105        CHECK_EQ(mRefCount, 0);
106        delete this;
107        return;
108    }
109
110    int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
111    if (prevCount == 1) {
112        if (mObserver == NULL) {
113            delete this;
114            return;
115        }
116
117        mObserver->signalBufferReturned(this);
118    }
119    CHECK(prevCount > 0);
120}
121
122void MediaBuffer::claim() {
123    CHECK(mObserver != NULL);
124    CHECK_EQ(mRefCount, 1);
125
126    mRefCount = 0;
127}
128
129void MediaBuffer::add_ref() {
130    (void) __sync_fetch_and_add(&mRefCount, 1);
131}
132
133void *MediaBuffer::data() const {
134    CHECK(mGraphicBuffer == NULL);
135    return mData;
136}
137
138size_t MediaBuffer::size() const {
139    CHECK(mGraphicBuffer == NULL);
140    return mSize;
141}
142
143size_t MediaBuffer::range_offset() const {
144    return mRangeOffset;
145}
146
147size_t MediaBuffer::range_length() const {
148    return mRangeLength;
149}
150
151void MediaBuffer::set_range(size_t offset, size_t length) {
152    if ((mGraphicBuffer == NULL) && (offset + length > mSize)) {
153        ALOGE("offset = %zu, length = %zu, mSize = %zu", offset, length, mSize);
154    }
155    CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
156
157    mRangeOffset = offset;
158    mRangeLength = length;
159}
160
161sp<GraphicBuffer> MediaBuffer::graphicBuffer() const {
162    return mGraphicBuffer;
163}
164
165sp<MetaData> MediaBuffer::meta_data() {
166    return mMetaData;
167}
168
169void MediaBuffer::reset() {
170    mMetaData->clear();
171    set_range(0, mSize);
172}
173
174MediaBuffer::~MediaBuffer() {
175    CHECK(mObserver == NULL);
176
177    if (mOwnsData && mData != NULL && mMemory == NULL) {
178        free(mData);
179        mData = NULL;
180    }
181
182    if (mOriginal != NULL) {
183        mOriginal->release();
184        mOriginal = NULL;
185    }
186}
187
188void MediaBuffer::setObserver(MediaBufferObserver *observer) {
189    CHECK(observer == NULL || mObserver == NULL);
190    mObserver = observer;
191}
192
193void MediaBuffer::setNextBuffer(MediaBuffer *buffer) {
194    mNextBuffer = buffer;
195}
196
197MediaBuffer *MediaBuffer::nextBuffer() {
198    return mNextBuffer;
199}
200
201int MediaBuffer::refcount() const {
202    return mRefCount;
203}
204
205MediaBuffer *MediaBuffer::clone() {
206    CHECK(mGraphicBuffer == NULL);
207
208    MediaBuffer *buffer = new MediaBuffer(mData, mSize);
209    buffer->set_range(mRangeOffset, mRangeLength);
210    buffer->mMetaData = new MetaData(*mMetaData.get());
211
212    add_ref();
213    buffer->mOriginal = this;
214
215    return buffer;
216}
217
218}  // namespace android
219