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 "MediaBufferGroup"
18#include <utils/Log.h>
19
20#include <media/stagefright/foundation/ADebug.h>
21#include <media/stagefright/MediaBuffer.h>
22#include <media/stagefright/MediaBufferGroup.h>
23
24namespace android {
25
26MediaBufferGroup::MediaBufferGroup()
27    : mFirstBuffer(NULL),
28      mLastBuffer(NULL) {
29}
30
31MediaBufferGroup::~MediaBufferGroup() {
32    MediaBuffer *next;
33    for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
34         buffer = next) {
35        next = buffer->nextBuffer();
36
37        CHECK_EQ(buffer->refcount(), 0);
38
39        buffer->setObserver(NULL);
40        buffer->release();
41    }
42}
43
44void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
45    Mutex::Autolock autoLock(mLock);
46
47    buffer->setObserver(this);
48
49    if (mLastBuffer) {
50        mLastBuffer->setNextBuffer(buffer);
51    } else {
52        mFirstBuffer = buffer;
53    }
54
55    mLastBuffer = buffer;
56}
57
58status_t MediaBufferGroup::acquire_buffer(
59        MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
60    Mutex::Autolock autoLock(mLock);
61
62    for (;;) {
63        MediaBuffer *freeBuffer = NULL;
64        MediaBuffer *freeBufferPrevious = NULL;
65        MediaBuffer *buffer = NULL;
66        MediaBuffer *bufferPrevious = NULL;
67        size_t smallest = requestedSize;
68        for (buffer = mFirstBuffer;
69             buffer != NULL; buffer = buffer->nextBuffer()) {
70            if (buffer->refcount() == 0) {
71               if (buffer->size() >= requestedSize) {
72                   break;
73               } else if (buffer->size() < smallest) {
74                   freeBuffer = buffer;
75                   freeBufferPrevious = bufferPrevious;
76               }
77            }
78            bufferPrevious = buffer;
79        }
80
81        if (buffer == NULL && freeBuffer != NULL) {
82            ALOGV("allocate new buffer, requested size %zu vs available %zu",
83                    requestedSize, freeBuffer->size());
84            size_t allocateSize = requestedSize;
85            if (requestedSize < SIZE_MAX / 3) {
86                allocateSize = requestedSize * 3 / 2;
87            }
88            MediaBuffer *newBuffer = new MediaBuffer(allocateSize);
89            newBuffer->setObserver(this);
90            if (freeBuffer == mFirstBuffer) {
91                mFirstBuffer = newBuffer;
92            }
93            if (freeBuffer == mLastBuffer) {
94                mLastBuffer = newBuffer;
95            }
96            newBuffer->setNextBuffer(freeBuffer->nextBuffer());
97            if (freeBufferPrevious != NULL) {
98                freeBufferPrevious->setNextBuffer(newBuffer);
99            }
100            freeBuffer->setObserver(NULL);
101            freeBuffer->release();
102
103            buffer = newBuffer;
104        }
105
106        if (buffer != NULL) {
107            buffer->add_ref();
108            buffer->reset();
109
110            *out = buffer;
111            goto exit;
112        }
113
114        if (nonBlocking) {
115            *out = NULL;
116            return WOULD_BLOCK;
117        }
118
119        // All buffers are in use. Block until one of them is returned to us.
120        mCondition.wait(mLock);
121    }
122
123exit:
124    return OK;
125}
126
127void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
128    Mutex::Autolock autoLock(mLock);
129    mCondition.signal();
130}
131
132}  // namespace android
133