1 /*
2 * Copyright (C) 2023 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_NDEBUG 0
18
19 #include "Buffer.h"
20 #include <inttypes.h>
21 #include <log/log.h>
22
23 namespace android {
24 namespace webcam {
25
BufferManager(BufferCreatorAndDestroyer * crD)26 BufferManager::BufferManager(BufferCreatorAndDestroyer* crD) : mCrD(crD) {
27 if (crD == nullptr) {
28 return;
29 }
30
31 std::vector<std::shared_ptr<Buffer>> producerBuffers;
32 if (mCrD->allocateAndMapBuffers(&mConsumerBufferItem.buffer, &producerBuffers) != Status::OK) {
33 return;
34 }
35 mConsumerBufferItem.state = BufferState::FREE;
36 for (auto& buf : producerBuffers) {
37 mProducerBufferItems.emplace_back(buf, BufferState::FREE);
38 }
39 mInited = true;
40 }
41
~BufferManager()42 BufferManager::~BufferManager() {
43 std::vector<std::shared_ptr<Buffer>> producerBuffers;
44 for (auto& buf : mProducerBufferItems) {
45 producerBuffers.push_back(buf.buffer);
46 }
47 mCrD->destroyBuffers(mConsumerBufferItem.buffer, producerBuffers);
48 mConsumerBufferItem.buffer = nullptr;
49 mProducerBufferItems.clear();
50 }
51
getFreeBufferIfAvailable()52 Buffer* BufferManager::getFreeBufferIfAvailable() {
53 // Producer call
54 std::unique_lock<std::mutex> l(mBufferLock);
55 for (auto& bufferItem : mProducerBufferItems) {
56 if (bufferItem.state == BufferState::FREE) {
57 bufferItem.state = BufferState::IN_USE;
58 return bufferItem.buffer.get();
59 }
60 }
61 for (const auto& bufferItem : mProducerBufferItems) {
62 uint64_t bufferTs = bufferItem.buffer->getTimestamp();
63 ALOGV("%s: Buffer at state %d, ts %" PRIu64 ", v4l2 index %u",
64 __FUNCTION__, (int)bufferItem.state, bufferTs,
65 bufferItem.buffer->getIndex());
66 }
67 return nullptr;
68 }
69
filledProducerBufferAvailableLocked(uint32_t * index)70 bool BufferManager::filledProducerBufferAvailableLocked(uint32_t* index) {
71 uint32_t i = 0;
72 bool found = false;
73 uint32_t foundIndex = 0;
74 uint64_t ts = 0;
75 // Try to get the latest filled buffer.
76 for (auto& bufferItem : mProducerBufferItems) {
77 uint64_t bufferTs = bufferItem.buffer->getTimestamp();
78 ALOGV("%s: Buffer at index i %u : state %d, ts %" PRIu64 ", v4l2 index %u", __FUNCTION__,
79 i, (int)bufferItem.state, bufferTs, bufferItem.buffer->getIndex());
80 if (bufferItem.state == BufferState::FILLED) {
81 if (bufferTs > ts) {
82 if (index != nullptr) {
83 *index = i;
84 }
85 ts = bufferTs;
86 found = true;
87 foundIndex = i;
88 }
89 }
90 i++;
91 }
92 // Actually cancel older buffers
93 uint32_t j = 0;
94 for (auto& bufferItem : mProducerBufferItems) {
95 if (bufferItem.state == BufferState::FILLED && j != foundIndex) {
96 bufferItem.state = BufferState::FREE;
97 }
98 j++;
99 }
100 return found;
101 }
102
getFilledBufferAndSwap()103 Buffer* BufferManager::getFilledBufferAndSwap() {
104 // Consumer call
105 // Wait for a producer buffer item state to be FILLED
106 // and swap consumer and producer buffer
107 std::unique_lock<std::mutex> l(mBufferLock);
108 uint32_t index = 0;
109 while (!filledProducerBufferAvailableLocked(&index)) {
110 // TODO(b/267794640): Add a timeout to recover in case of a deadlock.
111 // Wait till the producer side has filled the buffer.
112 mProducerBufferFilled.wait(l);
113 }
114 // Mark it free so that the producer can start filling it.
115 mConsumerBufferItem.state = BufferState::FREE;
116 std::swap(mConsumerBufferItem, mProducerBufferItems[index]);
117 // Now the consumer buffer is busy
118 mConsumerBufferItem.state = BufferState::IN_USE;
119 return mConsumerBufferItem.buffer.get();
120 }
121
changeProducerBufferStateLocked(Buffer * buffer,BufferState newState)122 bool BufferManager::changeProducerBufferStateLocked(Buffer* buffer, BufferState newState) {
123 bool found = false;
124 uint32_t i = 0;
125 for (auto& bufferItem : mProducerBufferItems) {
126 if (buffer->getIndex() == bufferItem.buffer->getIndex()) {
127 found = true;
128 break;
129 }
130 i++;
131 }
132 if (!found) {
133 ALOGE("%s queuing incorrect buffer, filled buffer index %u", __FUNCTION__,
134 buffer->getIndex());
135 return false;
136 }
137
138 mProducerBufferItems[i].state = newState;
139 return true;
140 }
141
cancelBuffer(Buffer * buffer)142 Status BufferManager::cancelBuffer(Buffer* buffer) {
143 std::unique_lock<std::mutex> l(mBufferLock);
144 if (!changeProducerBufferStateLocked(buffer, BufferState::FREE)) {
145 return Status::ERROR;
146 }
147 return Status::OK;
148 }
149
queueFilledBuffer(Buffer * buffer)150 Status BufferManager::queueFilledBuffer(Buffer* buffer) {
151 std::unique_lock<std::mutex> l(mBufferLock);
152
153 if (!changeProducerBufferStateLocked(buffer, BufferState::FILLED)) {
154 return Status::ERROR;
155 }
156
157 mProducerBufferFilled.notify_one();
158 return Status::OK;
159 }
160
161 } // namespace webcam
162 } // namespace android
163