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