1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "appsrc_memory.h"
17 #include "avdatasrcmemory.h"
18 #include "media_dfx.h"
19 #include "media_log.h"
20 #include "media_errors.h"
21 #include "securec.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AppSrcMemory"};
25 }
26
27 namespace OHOS {
28 namespace Media {
29 // Check whether (srcB, endB) belongs to (srcA, endA)
IsInnerRange(uint32_t srcA,uint32_t endA,uint32_t srcB,uint32_t endB)30 static bool IsInnerRange(uint32_t srcA, uint32_t endA, uint32_t srcB, uint32_t endB)
31 {
32 MEDIA_LOGD("srcA is: %{public}u, endA is: %{public}u, srcB is: %{public}u, endB is: %{public}u,",
33 srcA, endA, srcB, endB);
34 if (srcA < endA) {
35 return srcB < endB && srcB >= srcA && endB <= endA;
36 } else {
37 return (srcB < endB && srcB >= srcA && endB >= srcA) || (srcB < endB && srcB <= endA && endB <= endA) ||
38 (srcB >= srcA && endB <= endA);
39 }
40 }
41
AppsrcMemory()42 AppsrcMemory::AppsrcMemory()
43 {
44 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
45 }
46
~AppsrcMemory()47 AppsrcMemory::~AppsrcMemory()
48 {
49 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
50 }
51
GetBufferSize() const52 uint32_t AppsrcMemory::GetBufferSize() const
53 {
54 return bufferSize_;
55 }
56
GetMem()57 std::shared_ptr<AVSharedMemory> AppsrcMemory::GetMem()
58 {
59 return mem_;
60 }
61
GetFreeSize() const62 uint32_t AppsrcMemory::GetFreeSize() const
63 {
64 MEDIA_LOGD("GetFreeSize, begin is: %{public}u, end is: %{public}u, availableBegin is: %{public}u",
65 begin_, end_, availableBegin_);
66 uint32_t freeSize;
67 if (noFreeBuffer_) {
68 freeSize = 0;
69 } else {
70 uint32_t end = end_;
71 if (!unreturnedBuffers_.empty()) {
72 MEDIA_LOGD("unreturnedBuffers begin: %{public}u - %{public}u",
73 unreturnedBuffers_.front().first, unreturnedBuffers_.front().second);
74 end = unreturnedBuffers_.front().first;
75 }
76 freeSize = begin_ <= end ? end - begin_ + 1 : bufferSize_ - begin_ + end + 1;
77 }
78 MEDIA_LOGD("GetFreeSize is: %{public}u", freeSize);
79 MediaTrace::CounterTrace("AppsrcMemory::freeSize", freeSize);
80 return freeSize;
81 }
82
GetAvailableSize() const83 uint32_t AppsrcMemory::GetAvailableSize() const
84 {
85 MEDIA_LOGD("GetAvailableSize, begin is: %{public}u, end is: %{public}u, availableBegin is: %{public}u",
86 begin_, end_, availableBegin_);
87 uint32_t availableSize;
88 if (availableBegin_ == begin_ && noAvailableBuffer_) {
89 availableSize = 0;
90 } else {
91 availableSize = availableBegin_ < begin_ ?
92 begin_ - availableBegin_ :
93 bufferSize_ - availableBegin_ + begin_;
94 }
95 MEDIA_LOGD("GetAvailableSize is: %{public}u", availableSize);
96 MediaTrace::CounterTrace("AppsrcMemory::availableSize", availableSize);
97 return availableSize;
98 }
99
GetBeginPos() const100 uint32_t AppsrcMemory::GetBeginPos() const
101 {
102 return begin_;
103 }
104
GetAvailableBeginPos() const105 uint32_t AppsrcMemory::GetAvailableBeginPos() const
106 {
107 return availableBegin_;
108 }
109
GetPushOffset() const110 uint64_t AppsrcMemory::GetPushOffset() const
111 {
112 return pushOffset_;
113 }
114
GetFilePos() const115 uint64_t AppsrcMemory::GetFilePos() const
116 {
117 return filePos_;
118 }
119
SetBufferSize(uint32_t bufferSize)120 void AppsrcMemory::SetBufferSize(uint32_t bufferSize)
121 {
122 bufferSize_ = bufferSize;
123 MEDIA_LOGD("Set bufferSize_ is %{public}u", bufferSize_);
124 }
125
SetMem(std::shared_ptr<AVSharedMemory> mem)126 void AppsrcMemory::SetMem(std::shared_ptr<AVSharedMemory> mem)
127 {
128 mem_ = mem;
129 }
130
SetNoFreeBuffer(bool flag)131 void AppsrcMemory::SetNoFreeBuffer(bool flag)
132 {
133 if (noFreeBuffer_ != flag) {
134 noFreeBuffer_ = flag;
135 MEDIA_LOGD("noFreeBuffer_ set to: %{public}u", noFreeBuffer_);
136 }
137 }
138
SetNoAvailableBuffer(bool flag)139 void AppsrcMemory::SetNoAvailableBuffer(bool flag)
140 {
141 if (noAvailableBuffer_ != flag) {
142 noAvailableBuffer_ = flag;
143 MEDIA_LOGD("noAvailableBuffer_ set to: %{public}u", noAvailableBuffer_);
144 }
145 }
146
ResetMemParam()147 void AppsrcMemory::ResetMemParam()
148 {
149 filePos_ = 0;
150 begin_ = 0;
151 end_ = bufferSize_ - 1;
152 availableBegin_ = 0;
153 pushOffset_ = 0;
154 noFreeBuffer_ = false;
155 noAvailableBuffer_ = true;
156 }
157
RestoreMemParam()158 void AppsrcMemory::RestoreMemParam()
159 {
160 availableBegin_ = 0;
161 end_ = bufferSize_ - 1;
162 }
163
SeekAndChangePos(uint64_t pos)164 void AppsrcMemory::SeekAndChangePos(uint64_t pos)
165 {
166 MEDIA_LOGD("Enter SeekAndChangePos");
167 pushOffset_ = pos;
168 bool hasUnreturnedBuffer = (((end_ + 1) % bufferSize_) != availableBegin_) ? true : false;
169 uint32_t availableSize = GetAvailableSize();
170 // Check availableBuffer is Successive and seek location is cached
171 if ((IsMemSuccessive() || noFreeBuffer_) && filePos_ - availableSize <= pos && filePos_ >= pos) {
172 // if availableBuffer is Successive and seek location is cached, Adjust end_ according to hasUnreturnedBuffer
173 if (hasUnreturnedBuffer) {
174 uint32_t unusedBufferEnd = (availableBegin_ + availableSize - (filePos_ - pos)) % bufferSize_;
175 MEDIA_LOGD("unusedBuffers push begin: %{public}u, end: %{public}u", availableBegin_, unusedBufferEnd);
176 PushUnusedBuffers({availableBegin_, unusedBufferEnd});
177 availableBegin_ = begin_ - (filePos_ - pos);
178 } else {
179 uint32_t pad = noFreeBuffer_ ? bufferSize_ : 0;
180 availableBegin_ = (begin_ + pad) - (filePos_ - pos);
181 end_ = availableBegin_ == 0 ? bufferSize_ - 1 : availableBegin_ - 1;
182 }
183 } else if (filePos_ - availableSize <= pos && filePos_ >= pos) {
184 // seek location is cached
185 if (hasUnreturnedBuffer) {
186 uint32_t unusedBufferEnd = (availableBegin_ + availableSize - (filePos_ - pos)) % bufferSize_;
187 MEDIA_LOGD("unusedBuffers push begin: %{public}u, end: %{public}u", availableBegin_, unusedBufferEnd);
188 PushUnusedBuffers({availableBegin_, unusedBufferEnd});
189 availableBegin_ = ((begin_ + bufferSize_) - (filePos_ - pos)) % bufferSize_;
190 } else {
191 availableBegin_ = ((begin_ + bufferSize_) - (filePos_ - pos)) % bufferSize_;
192 end_ = availableBegin_ == 0 ? bufferSize_ - 1 : availableBegin_ - 1;
193 }
194 } else {
195 // seek location not cached
196 filePos_ = pos;
197 begin_ = availableBegin_;
198 if (!hasUnreturnedBuffer) {
199 end_ = availableBegin_ == 0 ? bufferSize_ - 1 : availableBegin_ - 1;
200 }
201 SetNoAvailableBuffer(true);
202 }
203 availableSize = GetAvailableSize();
204 if (availableSize != bufferSize_) {
205 SetNoFreeBuffer(false);
206 }
207 }
208
PullBufferAndChangePos(uint32_t readSize)209 void AppsrcMemory::PullBufferAndChangePos(uint32_t readSize)
210 {
211 MEDIA_LOGD("Enter PullBufferAndChangePos");
212 begin_ = (begin_ + readSize) % bufferSize_;
213 if (begin_ == (end_ + 1) % bufferSize_) {
214 SetNoFreeBuffer(true);
215 }
216 SetNoAvailableBuffer(false);
217 filePos_ += readSize;
218 }
219
PushBufferAndChangePos(uint32_t pushSize,bool isCopy)220 void AppsrcMemory::PushBufferAndChangePos(uint32_t pushSize, bool isCopy)
221 {
222 MEDIA_LOGD("Enter PushBufferAndChangePos");
223 if (isCopy) {
224 if ((end_ + 1) % bufferSize_ == availableBegin_) {
225 end_ = (end_ + pushSize) % bufferSize_;
226 } else {
227 PushUnusedBuffers({availableBegin_, (availableBegin_ + pushSize) % bufferSize_});
228 }
229 }
230 pushOffset_ += pushSize;
231 availableBegin_ = (availableBegin_ + pushSize) % bufferSize_;
232 if (availableBegin_ == begin_) {
233 SetNoAvailableBuffer(true);
234 }
235 }
236
FreeBufferAndChangePos(uint32_t offset,uint32_t length,bool isCopymode)237 bool AppsrcMemory::FreeBufferAndChangePos(uint32_t offset, uint32_t length, bool isCopymode)
238 {
239 MEDIA_LOGD("Enter FreeBufferAndChangePos");
240 if ((end_ + 1) % bufferSize_ != offset && !isCopymode) {
241 // Check the buffer after end_ is unusedbuffer, and Re-mark as freeBuffer
242 RemoveUnusedBuffer();
243 // Check the buffer to be returned is unreturnedbuffer and adjust unusedBuffers_ and unreturnedBuffers_
244 bool isProcessed = ProcessBuffer(offset, length);
245 if (isProcessed) {
246 return true;
247 }
248 if ((end_ + 1) % bufferSize_ != offset) {
249 CHECK_AND_RETURN_RET(PushBufferToUnreturnedBuffers(offset, length), false);
250 }
251 }
252 end_ = offset + length - 1;
253 SetNoFreeBuffer(false);
254 return true;
255 }
256
CopyBufferAndChangePos(std::shared_ptr<AppsrcMemory> & mem)257 bool AppsrcMemory::CopyBufferAndChangePos(std::shared_ptr<AppsrcMemory> &mem)
258 {
259 MEDIA_LOGD("Enter CopyBufferAndChangePos");
260 uint8_t *dstBase = std::static_pointer_cast<AVDataSrcMemory>(mem_)->GetInnerBase();
261 uint8_t *srcBase = std::static_pointer_cast<AVDataSrcMemory>(mem->GetMem())->GetInnerBase();
262 uint32_t size = mem->GetBufferSize();
263 uint32_t copyBegin = mem->GetAvailableBeginPos();
264 uint32_t availableSize = mem->GetAvailableSize();
265 if (availableSize && mem->IsMemSuccessive()) {
266 MEDIA_LOGD("Copy buffer, and buffer size is: %{public}u", availableSize);
267 errno_t rc = memcpy_s(dstBase, availableSize, srcBase + copyBegin, availableSize);
268 CHECK_AND_RETURN_RET_LOG(rc == EOK, false, "get mem is failed");
269 } else if (availableSize) {
270 uint32_t copySize = size - copyBegin;
271 MEDIA_LOGD("Copy buffer, and buffer size is: %{public}u", copySize);
272 errno_t rc = memcpy_s(dstBase, copySize, srcBase + copyBegin, copySize);
273 CHECK_AND_RETURN_RET_LOG(rc == EOK, false, "get mem is failed");
274 dstBase += copySize;
275 copySize = availableSize - (size - copyBegin);
276 if (copySize) {
277 MEDIA_LOGD("Copy buffer, and buffer size is: %{public}u", copySize);
278 rc = memcpy_s(dstBase, copySize, srcBase, copySize);
279 CHECK_AND_RETURN_RET_LOG(rc == EOK, false, "get mem is failed");
280 }
281 }
282 begin_ = availableSize;
283 filePos_ = mem->GetFilePos();
284 pushOffset_ = mem->GetPushOffset();
285 if (availableSize == size) {
286 mem->SetMem(nullptr);
287 mem = nullptr;
288 } else if (availableSize) {
289 mem->PushUnusedBuffers({copyBegin, mem->GetBeginPos()});
290 }
291 PrintCurPos();
292 MEDIA_LOGD("Exit CopyBufferAndChangePos");
293 return true;
294 }
295
RemoveUnusedBuffer()296 void AppsrcMemory::RemoveUnusedBuffer()
297 {
298 MEDIA_LOGD("Enter RemoveUnusedBuffer");
299 while (!unusedBuffers_.empty() && (end_ + 1) % bufferSize_ == unusedBuffers_.front().first) {
300 end_ = unusedBuffers_.front().second - 1;
301 MEDIA_LOGI("unusedBuffers pop %{public}u - %{public}u",
302 unusedBuffers_.front().first, unusedBuffers_.front().second);
303 unusedBuffers_.pop();
304 }
305 }
306
ProcessBuffer(uint32_t offset,uint32_t length)307 bool AppsrcMemory::ProcessBuffer(uint32_t offset, uint32_t length)
308 {
309 MEDIA_LOGD("Enter ProcessBuffer");
310 if ((end_ + 1) % bufferSize_ == offset) {
311 return false;
312 }
313 std::deque<std::pair<uint32_t, uint32_t>>::iterator iter;
314 bool flag = IsUnreturnedBuffer(offset, length, iter);
315 if (flag) {
316 while (!unusedBuffers_.empty() && iter != unreturnedBuffers_.end() &&
317 iter->first == unusedBuffers_.front().first) {
318 MEDIA_LOGI("unusedBuffers %{public}u - %{public}u",
319 unusedBuffers_.front().first, unusedBuffers_.front().second);
320 MEDIA_LOGI("iter %{public}u - %{public}u", iter->first, iter->second);
321 if (iter->second == unusedBuffers_.front().second) {
322 iter = unreturnedBuffers_.erase(iter);
323 MEDIA_LOGD("unreturnedBuffers pop");
324 } else {
325 iter->first = unusedBuffers_.front().second;
326 MEDIA_LOGD("unreturnedBuffers first change to : %{public}u", iter->first);
327 }
328 unusedBuffers_.pop();
329 MEDIA_LOGD("unusedBuffers pop");
330 }
331 return true;
332 }
333
334 return false;
335 }
336
IsUnreturnedBuffer(uint32_t offset,uint32_t length,std::deque<std::pair<uint32_t,uint32_t>>::iterator & iter)337 bool AppsrcMemory::IsUnreturnedBuffer(uint32_t offset, uint32_t length,
338 std::deque<std::pair<uint32_t, uint32_t>>::iterator &iter)
339 {
340 uint32_t pad;
341 for (iter = unreturnedBuffers_.begin(); iter != unreturnedBuffers_.end(); ++iter) {
342 pad = iter->first < iter->second ? 0 : bufferSize_;
343 if (!IsInnerRange(iter->first, iter->second + pad, offset, offset + length)) {
344 continue;
345 }
346 if (offset == iter->first && offset + length == iter->second + pad) {
347 iter = unreturnedBuffers_.erase(iter);
348 MEDIA_LOGD("unreturnedBuffers pop");
349 } else if (offset == iter->first) {
350 iter->first = (offset + length) % bufferSize_;
351 MEDIA_LOGD("unreturnedBuffers first change to : %{public}u", iter->first);
352 } else if (offset + length == iter->second + pad) {
353 iter->second = offset;
354 MEDIA_LOGD("unreturnedBuffers second change to : %{public}u", iter->second);
355 } else {
356 iter = unreturnedBuffers_.insert(iter, {iter->first, offset});
357 MEDIA_LOGD("unreturnedBuffers insert : %{public}u, %{public}u", iter->first, offset);
358 (iter + 1)->first = (offset + length) % bufferSize_;
359 MEDIA_LOGD("unreturnedBuffers first change to : %{public}u", (iter + 1)->first);
360 }
361 return true;
362 }
363 return false;
364 }
365
PushBufferToUnreturnedBuffers(uint32_t offset,uint32_t length)366 bool AppsrcMemory::PushBufferToUnreturnedBuffers(uint32_t offset, uint32_t length)
367 {
368 MEDIA_LOGD("Enter PushBufferToUnreturnedBuffers");
369 CHECK_AND_RETURN_RET_LOG(unreturnedBuffers_.empty() || !IsInnerRange(unreturnedBuffers_.begin()->first,
370 unreturnedBuffers_.rbegin()->second, offset, (offset + length) % bufferSize_),
371 false, "mempool error, end_ is %{public}u offset is %{public}u", end_, offset)
372 unreturnedBuffers_.push_back({(end_ + 1) % bufferSize_, offset});
373 MEDIA_LOGD("unreturnedBuffers push begin: %{public}u, end: %{public}u",
374 (end_ + 1) % bufferSize_, offset);
375 return true;
376 }
377
IsMemSuccessive()378 bool AppsrcMemory::IsMemSuccessive()
379 {
380 return availableBegin_ < begin_;
381 }
382
IsNeedCopy(uint32_t copySize)383 bool AppsrcMemory::IsNeedCopy(uint32_t copySize)
384 {
385 return copySize > (bufferSize_ - availableBegin_) ? true : false;
386 }
387
PushUnusedBuffers(std::pair<uint32_t,uint32_t> unusedBuffer)388 void AppsrcMemory::PushUnusedBuffers(std::pair<uint32_t, uint32_t> unusedBuffer)
389 {
390 unusedBuffers_.push(unusedBuffer);
391 MEDIA_LOGI("unusedBuffers push %{public}u - %{public}u", unusedBuffer.first, unusedBuffer.second);
392 }
393
PrintCurPos()394 void AppsrcMemory::PrintCurPos()
395 {
396 MEDIA_LOGD("free mem begin is: %{public}u, free mem end is: %{public}u,"
397 "available mem begin is: %{public}u, filePos is: %{public}" PRIu64 "",
398 begin_, end_, availableBegin_, filePos_);
399 }
400
CheckBufferUsage()401 void AppsrcMemory::CheckBufferUsage()
402 {
403 MEDIA_LOGD("Enter CheckBufferUsage");
404 size_t queueSize = unusedBuffers_.size();
405 for (size_t i = 0; i < queueSize; i++) {
406 MEDIA_LOGD("unusedBuffers begin: %{public}u, end: %{public}u",
407 unusedBuffers_.front().first, unusedBuffers_.front().second);
408 unusedBuffers_.push(unusedBuffers_.front());
409 unusedBuffers_.pop();
410 }
411 for (auto i = unreturnedBuffers_.begin(); i != unreturnedBuffers_.end(); ++i) {
412 MEDIA_LOGD("unreturnedBuffers begin: %{public}u, end: %{public}u", i->first, i->second);
413 }
414 }
415 }
416 }