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 24 namespace android { 25 26 // std::min is not constexpr in C++11 27 template<typename T> 28 constexpr T MIN(const T &a, const T &b) { return a <= b ? a : b; } 29 30 // MediaBufferGroup may create shared memory buffers at a 31 // smaller threshold than an isolated new MediaBuffer. 32 static const size_t kSharedMemoryThreshold = MIN( 33 (size_t)MediaBuffer::kSharedMemThreshold, (size_t)(4 * 1024)); 34 35 MediaBufferGroup::MediaBufferGroup(size_t growthLimit) : 36 mGrowthLimit(growthLimit) { 37 } 38 39 MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit) 40 : mGrowthLimit(growthLimit) { 41 42 if (buffer_size >= kSharedMemoryThreshold) { 43 ALOGD("creating MemoryDealer"); 44 // Using a single MemoryDealer is efficient for a group of shared memory objects. 45 // This loop guarantees that we use shared memory (no fallback to malloc). 46 47 size_t alignment = MemoryDealer::getAllocationAlignment(); 48 size_t augmented_size = buffer_size + sizeof(MediaBuffer::SharedControl); 49 size_t total = (augmented_size + alignment - 1) / alignment * alignment * buffers; 50 sp<MemoryDealer> memoryDealer = new MemoryDealer(total, "MediaBufferGroup"); 51 52 for (size_t i = 0; i < buffers; ++i) { 53 sp<IMemory> mem = memoryDealer->allocate(augmented_size); 54 if (mem.get() == nullptr) { 55 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size); 56 break; 57 } 58 MediaBuffer *buffer = new MediaBuffer(mem); 59 buffer->getSharedControl()->clear(); 60 add_buffer(buffer); 61 } 62 return; 63 } 64 65 // Non-shared memory allocation. 66 for (size_t i = 0; i < buffers; ++i) { 67 MediaBuffer *buffer = new MediaBuffer(buffer_size); 68 if (buffer->data() == nullptr) { 69 delete buffer; // don't call release, it's not properly formed 70 ALOGW("Only allocated %zu malloc buffers of size %zu", i, buffer_size); 71 break; 72 } 73 add_buffer(buffer); 74 } 75 } 76 77 MediaBufferGroup::~MediaBufferGroup() { 78 for (MediaBuffer *buffer : mBuffers) { 79 buffer->resolvePendingRelease(); 80 // If we don't release it, perhaps noone will release it. 81 LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0, 82 "buffer refcount %p = %d != 0", buffer, buffer->refcount()); 83 // actually delete it. 84 buffer->setObserver(nullptr); 85 buffer->release(); 86 } 87 } 88 89 void MediaBufferGroup::add_buffer(MediaBuffer *buffer) { 90 Mutex::Autolock autoLock(mLock); 91 92 buffer->setObserver(this); 93 mBuffers.emplace_back(buffer); 94 // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size()); 95 } 96 97 void MediaBufferGroup::gc(size_t freeBuffers) { 98 Mutex::Autolock autoLock(mLock); 99 100 size_t freeCount = 0; 101 for (auto it = mBuffers.begin(); it != mBuffers.end(); ) { 102 (*it)->resolvePendingRelease(); 103 if ((*it)->isDeadObject()) { 104 // The MediaBuffer has been deleted, why is it in the MediaBufferGroup? 105 LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d", 106 (*it), (*it)->refcount()); 107 } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) { 108 (*it)->setObserver(nullptr); 109 (*it)->release(); 110 it = mBuffers.erase(it); 111 } else { 112 ++it; 113 } 114 } 115 } 116 117 bool MediaBufferGroup::has_buffers() { 118 if (mBuffers.size() < mGrowthLimit) { 119 return true; // We can add more buffers internally. 120 } 121 for (MediaBuffer *buffer : mBuffers) { 122 buffer->resolvePendingRelease(); 123 if (buffer->refcount() == 0) { 124 return true; 125 } 126 } 127 return false; 128 } 129 130 status_t MediaBufferGroup::acquire_buffer( 131 MediaBuffer **out, bool nonBlocking, size_t requestedSize) { 132 Mutex::Autolock autoLock(mLock); 133 for (;;) { 134 size_t smallest = requestedSize; 135 MediaBuffer *buffer = nullptr; 136 auto free = mBuffers.end(); 137 for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) { 138 (*it)->resolvePendingRelease(); 139 if ((*it)->refcount() == 0) { 140 const size_t size = (*it)->size(); 141 if (size >= requestedSize) { 142 buffer = *it; 143 break; 144 } 145 if (size < smallest) { 146 smallest = size; // always free the smallest buf 147 free = it; 148 } 149 } 150 } 151 if (buffer == nullptr 152 && (free != mBuffers.end() || mBuffers.size() < mGrowthLimit)) { 153 // We alloc before we free so failure leaves group unchanged. 154 const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ? 155 requestedSize * 3 / 2 : requestedSize; 156 buffer = new MediaBuffer(allocateSize); 157 if (buffer->data() == nullptr) { 158 ALOGE("Allocation failure for size %zu", allocateSize); 159 delete buffer; // Invalid alloc, prefer not to call release. 160 buffer = nullptr; 161 } else { 162 buffer->setObserver(this); 163 if (free != mBuffers.end()) { 164 ALOGV("reallocate buffer, requested size %zu vs available %zu", 165 requestedSize, (*free)->size()); 166 (*free)->setObserver(nullptr); 167 (*free)->release(); 168 *free = buffer; // in-place replace 169 } else { 170 ALOGV("allocate buffer, requested size %zu", requestedSize); 171 mBuffers.emplace_back(buffer); 172 } 173 } 174 } 175 if (buffer != nullptr) { 176 buffer->add_ref(); 177 buffer->reset(); 178 *out = buffer; 179 return OK; 180 } 181 if (nonBlocking) { 182 *out = nullptr; 183 return WOULD_BLOCK; 184 } 185 // All buffers are in use, block until one of them is returned. 186 mCondition.wait(mLock); 187 } 188 // Never gets here. 189 } 190 191 void MediaBufferGroup::signalBufferReturned(MediaBuffer *) { 192 mCondition.signal(); 193 } 194 195 } // namespace android 196