• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
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 #define HST_LOG_TAG "DataPacker"
16 
17 #include <cstring>
18 #include "common/log.h"
19 #include "osal/task/autolock.h"
20 #include "securec.h"
21 #include "data_packer.h"
22 
23 namespace OHOS {
24 namespace Media {
25 using namespace Plugins;
26 using AVBufferPtr = std::shared_ptr<Buffer>;
27 #define EXEC_WHEN_GET(isGet, exec)     \
28     do {                               \
29         if (isGet) {                   \
30             exec;                      \
31         }                              \
32     } while (0)
33 
34 static const DataPacker::Position DATA_PACKER_INVALID_POSITION = DataPacker::Position(-1, 0, 0);
35 static constexpr size_t MIN_BUFFER_NUMBER_IN_DATA_PACKER = 30;
36 static constexpr size_t MAX_BUFFER_NUMBER_IN_DATA_PACKER = 10 * 1024 * 1024 / 4096;
37 
DataPacker()38 DataPacker::DataPacker() : mutex_(), que_(), size_(0), mediaOffset_(0), pts_(0), dts_(0),
39     prevGet_(DATA_PACKER_INVALID_POSITION), currentGet_(DATA_PACKER_INVALID_POSITION),
40     capacity_(MAX_BUFFER_NUMBER_IN_DATA_PACKER)
41 {
42     MEDIA_LOG_I("DataPacker ctor...");
43 }
44 
~DataPacker()45 DataPacker::~DataPacker()
46 {
47     MEDIA_LOG_I("DataPacker dtor...");
48     cvEmpty_.NotifyAll();
49     cvFull_.NotifyAll();
50     cvAllowRead_.NotifyAll();
51 }
52 
GetBufferSize(AVBufferPtr & ptr)53 inline static size_t GetBufferSize(AVBufferPtr& ptr)
54 {
55     return ptr->GetMemory()->GetSize();
56 }
57 
GetBufferWritableData(AVBufferPtr & ptr,size_t size,size_t position=0)58 inline static uint8_t* GetBufferWritableData(AVBufferPtr& ptr, size_t size, size_t position = 0)
59 {
60     return ptr->GetMemory()->GetWritableAddr(size, position);
61 }
62 
GetBufferReadOnlyData(AVBufferPtr & ptr)63 inline static const uint8_t* GetBufferReadOnlyData(AVBufferPtr& ptr)
64 {
65     return ptr->GetMemory()->GetReadOnlyData();
66 }
67 
PushData(AVBufferPtr & bufferPtr,uint64_t offset)68 void DataPacker::PushData(AVBufferPtr& bufferPtr, uint64_t offset)
69 {
70     size_t bufferSize = GetBufferSize(bufferPtr);
71     MEDIA_LOG_D("DataPacker PushData begin... buffer (offset " PUBLIC_LOG_U64 ", size " PUBLIC_LOG_ZU ")",
72                  offset, bufferSize);
73     FALSE_RETURN_MSG(bufferSize > 0, "Can not push zero length buffer.");
74 
75     AutoLock lock(mutex_);
76     if (que_.size() >= capacity_) {
77         MEDIA_LOG_D("DataPacker is full, waiting for pop.");
78         do {
79             cvFull_.WaitFor(lock, 1000,  // 1000 ms
80                 [this] { return que_.size() < capacity_ || stopped_.load(); });
81             if (stopped_.load()) {
82                 MEDIA_LOG_D("DataPacker stopped, so return.");
83                 return;
84             }
85         } while (que_.size() >= capacity_);
86     }
87 
88     size_ += GetBufferSize(bufferPtr);
89     if (que_.empty()) {
90         MEDIA_LOG_D("DataPacker que_ is empty.");
91         mediaOffset_ = offset;
92         dts_ = bufferPtr->dts;
93         pts_ = bufferPtr->pts;
94     }
95     que_.emplace_back(std::move(bufferPtr));
96     cvEmpty_.NotifyAll();
97     MEDIA_LOG_D("DataPacker PushData end. " PUBLIC_LOG_S, ToString().c_str());
98 }
99 
IsDataAvailable(uint64_t offset,uint32_t size)100 bool DataPacker::IsDataAvailable(uint64_t offset, uint32_t size)
101 {
102     AutoLock lock(mutex_);
103     return IsDataAvailableInternal(offset, size);
104 }
105 
IsDataAvailableInternal(uint64_t offset,uint32_t size)106 bool DataPacker::IsDataAvailableInternal(uint64_t offset, uint32_t size)
107 {
108     MEDIA_LOG_D("dataPacker (offset " PUBLIC_LOG_U64 ", size " PUBLIC_LOG_U32 "), curOffsetEnd is " PUBLIC_LOG_U64
109         ", income offset: " PUBLIC_LOG_U64 ", income size: " PUBLIC_LOG_U32,
110         mediaOffset_, size_.load(), mediaOffset_ + size_.load(), offset, size);
111     auto curOffsetTemp = mediaOffset_;
112     if (que_.empty() || offset < curOffsetTemp || offset > curOffsetTemp + size_) {
113         FlushInternal();
114         MEDIA_LOG_D("IsDataAvailable false, offset not in cached data, clear it.");
115         return false;
116     }
117     size_t bufCnt = que_.size();
118     uint64_t offsetEnd = offset + size;
119     uint64_t curOffsetEnd = mediaOffset_ + GetBufferSize(que_.front());
120     if (bufCnt == 1) {
121         MEDIA_LOG_D("IsDataAvailable bufCnt == 1, result " PUBLIC_LOG_D32, offsetEnd <= curOffsetEnd);
122         return offsetEnd <= curOffsetEnd;
123     }
124     auto preOffsetEnd = curOffsetEnd;
125     for (size_t i = 1; i < bufCnt; ++i) {
126         curOffsetEnd = preOffsetEnd + GetBufferSize(que_[i]);
127         if (curOffsetEnd >= offsetEnd) {
128             MEDIA_LOG_D("IsDataAvailable true, last buffer index " PUBLIC_LOG_ZU ", offsetEnd " PUBLIC_LOG_U64
129                 ", curOffsetEnd " PUBLIC_LOG_U64, i, offsetEnd, curOffsetEnd);
130             return true;
131         } else {
132             preOffsetEnd = curOffsetEnd;
133         }
134     }
135     if (preOffsetEnd >= offsetEnd || isEos_) {
136         MEDIA_LOG_D("IsDataAvailable true, use all buffers, last buffer index " PUBLIC_LOG_ZU ", offsetEnd "
137             PUBLIC_LOG_U64 ", curOffsetEnd " PUBLIC_LOG_U64, bufCnt - 1, offsetEnd, curOffsetEnd);
138         return true;
139     }
140     MEDIA_LOG_D("IsDataAvailable false, offsetEnd " PUBLIC_LOG_U64 ", curOffsetEnd " PUBLIC_LOG_U64,
141         offsetEnd, preOffsetEnd);
142     return false;
143 }
144 
PeekRange(uint64_t offset,uint32_t size,AVBufferPtr & bufferPtr)145 bool DataPacker::PeekRange(uint64_t offset, uint32_t size, AVBufferPtr& bufferPtr)
146 {
147     AutoLock lock(mutex_);
148     if (que_.empty()) {
149         MEDIA_LOG_D("DataPacker is empty, waiting for push.");
150         cvEmpty_.Wait(lock, [this] { return !que_.empty(); });
151     }
152 
153     return PeekRangeInternal(offset, size, bufferPtr, false);
154 }
155 
PeekRangeInternal(uint64_t offset,uint32_t size,AVBufferPtr & bufferPtr,bool isGet)156 bool DataPacker::PeekRangeInternal(uint64_t offset, uint32_t size, AVBufferPtr &bufferPtr, bool isGet)
157 {
158     MEDIA_LOG_D("PeekRangeInternal (offset, size) = (" PUBLIC_LOG_U64 ", " PUBLIC_LOG_U32 ")...", offset, size);
159     int32_t startIndex = 0; // The index of buffer that we first use
160     size_t copySize = 0;
161     uint32_t needCopySize = size;
162     uint32_t firstBufferOffset = 0;
163     uint8_t* dstPtr = GetBufferWritableData(bufferPtr, needCopySize);
164     FALSE_RETURN_V(dstPtr != nullptr, false);
165 
166     auto offsetEnd = offset + needCopySize;
167     auto curOffsetEnd = mediaOffset_ + GetBufferSize(que_[startIndex]);
168     if (offsetEnd <= curOffsetEnd) { // first buffer is enough
169         auto bufferOffset = static_cast<int32_t>(offset - mediaOffset_);
170         FALSE_RETURN_V_MSG_E(bufferOffset >= 0, false, "Copy buffer start position error.");
171         firstBufferOffset = bufferOffset;
172         copySize = CopyFirstBuffer(size, startIndex, dstPtr, bufferPtr, bufferOffset);
173         needCopySize -= copySize;
174         FALSE_LOG_MSG(needCopySize == 0, "First buffer is enough, but copySize is not enough");
175         EXEC_WHEN_GET(isGet, currentGet_ = Position(startIndex, firstBufferOffset, offset));
176         return true;
177     } else { // first buffer not enough
178         // Find the first buffer that should copy
179         uint64_t prevOffset; // The media offset of the startIndex buffer start byte
180         FALSE_RETURN_V_MSG_E(FindFirstBufferToCopy(offset, startIndex, prevOffset), false,
181             "Read offset(" PUBLIC_LOG_D64 ") size(" PUBLIC_LOG_D32 ") from " PUBLIC_LOG_S,
182             offset, size, ToString().c_str());
183         auto bufferOffset = static_cast<int32_t>(offset - prevOffset);
184         FALSE_RETURN_V_MSG_E(bufferOffset >= 0, false, "Copy buffer start position error.");
185         firstBufferOffset = bufferOffset;
186         copySize = CopyFirstBuffer(size, startIndex, dstPtr, bufferPtr, bufferOffset);
187 
188         needCopySize -= copySize;
189         if (needCopySize == 0) { // First buffer is enough
190             EXEC_WHEN_GET(isGet, currentGet_ = Position(startIndex, firstBufferOffset, offset));
191             return true;
192         }
193         dstPtr += copySize;
194 
195         // First buffer is not enough, copy from successive buffers
196         (void)CopyFromSuccessiveBuffer(prevOffset, offsetEnd, startIndex, dstPtr, needCopySize);
197     }
198     EXEC_WHEN_GET(isGet, currentGet_ = Position(startIndex, firstBufferOffset, offset));
199 
200     // Update to the real size, especially at the end.
201     bufferPtr->GetMemory()->UpdateDataSize(size - needCopySize);
202     return true;
203 }
204 
205 // Call IsDataAvailable() first before call GetRange
GetRange(uint64_t offset,uint32_t size,AVBufferPtr & bufferPtr)206 bool DataPacker::GetRange(uint64_t offset, uint32_t size, AVBufferPtr& bufferPtr)
207 {
208     MEDIA_LOG_D("DataPacker GetRange(offset, size) = (" PUBLIC_LOG_U64 ", "
209         PUBLIC_LOG_U32 ")...", offset, size);
210     FALSE_RETURN_V_MSG_E(bufferPtr && (!bufferPtr->IsEmpty()) && bufferPtr->GetMemory()->GetCapacity() >= size, false,
211         "GetRange input bufferPtr empty or capacity not enough.");
212 
213     AutoLock lock(mutex_);
214     if (que_.empty()) {
215         MEDIA_LOG_D("DataPacker is empty, waiting for push");
216         cvEmpty_.Wait(lock, [this] { return !que_.empty(); });
217     }
218 
219     FALSE_RETURN_V(!que_.empty(), false);
220     prevGet_ = currentGet_; // store last get position to prevGet_
221 
222     FALSE_RETURN_V(PeekRangeInternal(offset, size, bufferPtr, true), false);
223     if (isEos_ && size_ <= size) { // Is EOS, and this time get all the data.
224         FlushInternal();
225     } else {
226         if (prevGet_ < currentGet_) {
227             RemoveOldData(currentGet_);
228         }
229     }
230 
231     if (que_.size() < capacity_) {
232         cvFull_.NotifyOne();
233     }
234     return true;
235 }
236 
PreRemove(uint64_t preRemoveOffset,bool isPreRemove)237 void DataPacker::PreRemove(uint64_t preRemoveOffset, bool isPreRemove)
238 {
239     if (!isPreRemove) {
240         return;
241     }
242     int32_t index = 0;
243     uint32_t bufferOffset = 0;
244     uint64_t mediaOffset = preRemoveOffset;
245     uint64_t sum = 0;
246     for (index = 0; index < static_cast<int32_t>(que_.size()); index++) {
247         if (sum < preRemoveOffset && sum + GetBufferSize(que_[index]) >= preRemoveOffset) {
248             bufferOffset = preRemoveOffset - sum;
249             break;
250         }
251         sum += GetBufferSize(que_[index]);
252     }
253     MEDIA_LOG_D("DataPacker PreRemove, index: " PUBLIC_LOG_D32 ", bufferOffset: " PUBLIC_LOG_U32
254         ", mediaOffset: " PUBLIC_LOG_U64, index, bufferOffset, mediaOffset);
255     auto endPosition = Position(index, bufferOffset, mediaOffset);
256     RemoveOldData(endPosition);
257     MEDIA_LOG_D("DataPacker PreRemove, size: " PUBLIC_LOG_D32, static_cast<int32_t>(que_.size()));
258 }
259 
260 // GetRange in live play mode
261 //  1. not use offset
262 //  2. remove the data have been read
GetRange(uint32_t size,AVBufferPtr & bufferPtr,uint64_t preRemoveOffset,bool isPreRemove)263 bool DataPacker::GetRange(uint32_t size, AVBufferPtr& bufferPtr, uint64_t preRemoveOffset, bool isPreRemove)
264 {
265     MEDIA_LOG_D("GetRange(size) = (" PUBLIC_LOG_U32 "), preRemoveOffset: " PUBLIC_LOG_U64, size, preRemoveOffset);
266     FALSE_RETURN_V_MSG_E(bufferPtr && (!bufferPtr->IsEmpty()) && bufferPtr->GetMemory()->GetCapacity() >= size, false,
267         "Live play GetRange input bufferPtr empty or capacity not enough.");
268     AutoLock lock(mutex_);
269     if (que_.empty()) {
270         FALSE_RETURN_V_W(!isEos_, false);
271         MEDIA_LOG_D("DataPacker is empty, live play GetRange waiting for push");
272         cvEmpty_.Wait(lock, [this] { return !que_.empty() || isEos_; });
273         if (isEos_) {
274             MEDIA_LOG_D("Eos wakeup the cvEmpty ConditionVariable");
275             return false;
276         }
277     }
278     PreRemove(preRemoveOffset, isPreRemove);
279     FALSE_RETURN_V_MSG_W(!que_.empty(), false, "que_ is empty");
280     int32_t needCopySize = static_cast<int32_t>(size);
281     int32_t index = 0;
282     uint32_t lastBufferOffsetEnd = 0;
283     uint8_t* dstPtr = GetBufferWritableData(bufferPtr, size);
284     FALSE_RETURN_V_MSG_E(dstPtr != nullptr, false, "dstPtr is nullptr");
285     while (static_cast<uint32_t>(index) < que_.size()) {
286         AVBufferPtr& buffer = que_[index];
287         size_t bufferSize = GetBufferSize(buffer);
288         int32_t currCopySize = std::min(static_cast<int32_t>(bufferSize), needCopySize);
289         currCopySize = CopyFirstBuffer(currCopySize, index, dstPtr, bufferPtr, 0);
290         lastBufferOffsetEnd = currCopySize;
291         dstPtr += currCopySize;
292         needCopySize -= currCopySize;
293         if (needCopySize <= 0) { // it is enough
294             break;
295         }
296         index++;
297         lastBufferOffsetEnd = 0;
298     }
299     FALSE_LOG(needCopySize >= 0);
300     needCopySize = needCopySize < 0 ? 0 : needCopySize;
301     bufferPtr->GetMemory()->UpdateDataSize(size - needCopySize);
302     MEDIA_LOG_D("GetRange before remove, size: " PUBLIC_LOG_D32 ", index: " PUBLIC_LOG_D32 ", lastBufferOffsetEnd: "
303         PUBLIC_LOG_U32 ", mediaOffset: " PUBLIC_LOG_U64, static_cast<int32_t>(que_.size()),
304         index, lastBufferOffsetEnd, mediaOffset_ + size - needCopySize);
305     auto endPosition = Position(index, lastBufferOffsetEnd, mediaOffset_ + size - needCopySize);
306     RemoveOldData(endPosition); // Live play, remove the got data
307     MEDIA_LOG_D("GetRange after remove, size: " PUBLIC_LOG_D32, static_cast<int32_t>(que_.size()));
308     if (que_.size() < capacity_) {
309         cvFull_.NotifyOne();
310     }
311     return true;
312 }
313 
GetOrWaitDataAvailable(uint64_t offset,uint32_t size)314 bool DataPacker::GetOrWaitDataAvailable(uint64_t offset, uint32_t size)
315 {
316     MEDIA_LOG_D("GetOrWaitDataAvailable, offset: " PUBLIC_LOG_U64 ", size: " PUBLIC_LOG_U32 ", mediaOffset_: "
317         PUBLIC_LOG_U64 ", size_: " PUBLIC_LOG_U32, offset, size, mediaOffset_, size_.load());
318     AutoLock lock(mutex_);
319     if (!IsDataAvailableInternal(offset, size)) {
320         MEDIA_LOG_D("GetOrWaitDataAvailable, data is not available, start to wait.");
321         do {
322             auto ret = cvEmpty_.WaitFor(lock, 1000, [this, offset, size] () {
323                 return IsDataAvailableInternal(offset, size) || stopped_.load();
324             });
325             if (!ret) {
326                 MEDIA_LOG_E("GetOrWaitDataAvailable wait for data, time out");
327                 return false;
328             }
329             if (stopped_.load()) {
330                 MEDIA_LOG_D("DataPacker stopped, so return.");
331                 return false;
332             }
333         } while (!IsDataAvailableInternal(offset, size));
334     }
335     MEDIA_LOG_D("GetOrWaitDataAvailable get data success after wait.");
336     return true;
337 }
338 
Flush()339 void DataPacker::Flush()
340 {
341     MEDIA_LOG_I("DataPacker Flush called.");
342     AutoLock lock(mutex_);
343     FlushInternal();
344 }
345 
SetEos()346 void DataPacker::SetEos()
347 {
348     MEDIA_LOG_I("DataPacker SetEos called.");
349     AutoLock lock(mutex_);
350     isEos_ = true;
351     cvEmpty_.NotifyOne();
352     cvAllowRead_.NotifyOne();
353 }
354 
IsSupportPreDownload(bool isSupport)355 void DataPacker::IsSupportPreDownload(bool isSupport)
356 {
357     isSupportPreDownload_ = isSupport;
358     capacity_ = isSupportPreDownload_ ? MAX_BUFFER_NUMBER_IN_DATA_PACKER : MIN_BUFFER_NUMBER_IN_DATA_PACKER;
359 }
360 
IsEmpty()361 bool DataPacker::IsEmpty()
362 {
363     AutoLock lock(mutex_);
364     cvAllowRead_.NotifyOne();
365     return size_ > 0;
366 }
367 
Start()368 void DataPacker::Start()
369 {
370     MEDIA_LOG_I("DataPacker Start called.");
371     stopped_.store(false);
372 }
373 
Stop()374 void DataPacker::Stop()
375 {
376     MEDIA_LOG_I("DataPacker Stop called.");
377     FlushInternal();
378     stopped_.store(true);
379     cvEmpty_.NotifyAll(); // avoid some thread can not exit
380     cvFull_.NotifyAll();
381 }
382 
FlushInternal()383 void DataPacker::FlushInternal()
384 {
385     MEDIA_LOG_D("DataPacker FlushInternal called, que_ size: " PUBLIC_LOG_D32 ", capacity_: " PUBLIC_LOG_ZU,
386         static_cast<int32_t>(que_.size()), capacity_);
387     que_.clear();
388     size_ = 0;
389     mediaOffset_ = 0;
390     dts_ = 0;
391     pts_ = 0;
392     isEos_ = false;
393     prevGet_ = DATA_PACKER_INVALID_POSITION;
394     currentGet_ = DATA_PACKER_INVALID_POSITION;
395 }
396 
397 // Remove first removeSize data in the buffer
RemoveBufferContent(AVBufferPtr & buffer,size_t removeSize)398 void DataPacker::RemoveBufferContent(AVBufferPtr &buffer, size_t removeSize)
399 {
400     if (removeSize == 0) {
401         return;
402     }
403     auto memory = buffer->GetMemory();
404     FALSE_RETURN(removeSize < memory->GetSize());
405     auto copySize = memory->GetSize() - removeSize;
406     FALSE_LOG_MSG(memmove_s(memory->GetWritableAddr(copySize), memory->GetCapacity(),
407         memory->GetReadOnlyData(removeSize), copySize) == EOK, "memmove failed.");
408     FALSE_RETURN(UpdateWhenFrontDataRemoved(removeSize));
409 }
410 
411 // Remove consumed data, and make the remaining data continuous
412 // Consumed data - between prevGet_.first and currentGet_.first
413 // In order to make remaining data continuous, also remove the data before prevGet_.first
414 // Update to support live play mode, Remove the data before position
RemoveOldData(const Position & position)415 void DataPacker::RemoveOldData(const Position& position)
416 {
417     MEDIA_LOG_D("Before RemoveOldData " PUBLIC_LOG_S, ToString().c_str());
418     FALSE_LOG(RemoveTo(position));
419     if (que_.empty()) {
420         mediaOffset_ = 0;
421         size_ = 0;
422         pts_ = 0;
423         dts_ = 0;
424     } else {
425         pts_ = que_.front()->pts;
426         dts_ = que_.front()->dts;
427     }
428     MEDIA_LOG_D("After RemoveOldData " PUBLIC_LOG_S, ToString().c_str());
429 }
430 
RemoveTo(const Position & position)431 bool DataPacker::RemoveTo(const Position& position)
432 {
433     MEDIA_LOG_D("Remove to " PUBLIC_LOG_S, position.ToString().c_str());
434     size_t removeSize;
435     int32_t i = 0;
436     while (i < position.index && !que_.empty()) { // Remove all whole buffer before position.index
437         removeSize = GetBufferSize(que_.front());
438         FALSE_RETURN_V(UpdateWhenFrontDataRemoved(removeSize), false);
439         que_.pop_front();
440         i++;
441     }
442     FALSE_RETURN_V_W(!que_.empty(), true);
443 
444     // The last buffer
445     removeSize = GetBufferSize(que_.front());
446     // 1. If whole buffer should be removed
447     if (position.bufferOffset >= removeSize) {
448         FALSE_RETURN_V(UpdateWhenFrontDataRemoved(removeSize), false);
449         que_.pop_front();
450         return true;
451     }
452     // 2. Remove the front part of the buffer data
453     RemoveBufferContent(que_.front(), position.bufferOffset);
454     return true;
455 }
456 
UpdateWhenFrontDataRemoved(size_t removeSize)457 bool DataPacker::UpdateWhenFrontDataRemoved(size_t removeSize)
458 {
459     mediaOffset_ += removeSize;
460     FALSE_RETURN_V_MSG_E(size_.load() >= removeSize, false, "Total size(size_ " PUBLIC_LOG_U32
461         ") smaller than removeSize(" PUBLIC_LOG_ZU ")", size_.load(), removeSize);
462     size_ -= removeSize;
463     return true;
464 }
465 
466 // offset : from GetRange(offset, size)
467 // startIndex : out, find the first buffer should copy
468 // prevOffset : the first copied buffer's media offset.
FindFirstBufferToCopy(uint64_t offset,int32_t & startIndex,uint64_t & prevOffset)469 bool DataPacker::FindFirstBufferToCopy(uint64_t offset, int32_t &startIndex, uint64_t &prevOffset)
470 {
471     startIndex = 0;
472     prevOffset = mediaOffset_;
473     do {
474         if (offset >= prevOffset && offset - prevOffset < GetBufferSize(que_[startIndex])) {
475             return true;
476         }
477         prevOffset += GetBufferSize(que_[startIndex]);
478         startIndex++;
479     } while (static_cast<size_t>(startIndex) < que_.size());
480     return false;
481 }
482 
483 // size : the GetRange size
484 // dstPtr : copy data to here
485 // dstBufferPtr : the Buffer contains dstPtr, pass this parameter to update pts / dts.
486 // bufferOffset : the buffer offset that we start copy
CopyFirstBuffer(size_t size,int32_t index,uint8_t * dstPtr,AVBufferPtr & dstBufferPtr,int32_t bufferOffset)487 size_t DataPacker::CopyFirstBuffer(size_t size, int32_t index, uint8_t *dstPtr, AVBufferPtr& dstBufferPtr,
488     int32_t bufferOffset)
489 {
490     auto remainSize = static_cast<int32_t>(GetBufferSize(que_[index]) - bufferOffset);
491     FALSE_RETURN_V_MSG_E(remainSize > 0, 0, "Copy size can not be negative.");
492     size_t copySize = std::min(static_cast<size_t>(remainSize), size);
493     NZERO_LOG(memcpy_s(dstPtr, copySize,
494         GetBufferReadOnlyData(que_[index]) + bufferOffset, copySize));
495 
496     dstBufferPtr->pts = que_[index]->pts;
497     dstBufferPtr->dts = que_[index]->dts;
498     return copySize;
499 }
500 
501 // prevOffset : the media offset of the first byte in the startIndex + 1 buffer
502 // offsetEnd : calculate from GetRange(offset, size), offsetEnd = offset + size.
503 // startIndex : the index start copy data for this GetRange. CopyFromSuccessiveBuffer process from startIndex + 1.
504 // dstPtr : copy data to here
505 // needCopySize : in and out, indicate how many bytes still need to copy.
CopyFromSuccessiveBuffer(uint64_t prevOffset,uint64_t offsetEnd,int32_t startIndex,uint8_t * dstPtr,uint32_t & needCopySize)506 int32_t DataPacker::CopyFromSuccessiveBuffer(uint64_t prevOffset, uint64_t offsetEnd, int32_t startIndex,
507     uint8_t *dstPtr, uint32_t &needCopySize)
508 {
509     size_t copySize;
510     int32_t usedCount = 0;
511     prevOffset = prevOffset + GetBufferSize(que_[startIndex]);
512     for (size_t i = startIndex + 1; i < que_.size(); ++i) {
513         usedCount++;
514         uint64_t curOffsetEnd = prevOffset + GetBufferSize(que_[i]);
515         if (curOffsetEnd >= offsetEnd) { // This buffer is enough
516             NZERO_LOG(memcpy_s(dstPtr, needCopySize, GetBufferReadOnlyData(que_[i]), needCopySize));
517             needCopySize = 0;
518             return usedCount; // Finished copy buffer
519         } else {
520             copySize = GetBufferSize(que_[i]);
521             NZERO_LOG(memcpy_s(dstPtr, copySize, GetBufferReadOnlyData(que_[i]), copySize));
522             dstPtr += copySize;
523             needCopySize -= copySize;
524             prevOffset += copySize;
525         }
526     }
527     MEDIA_LOG_W("Processed all cached buffers, still not meet offsetEnd, maybe EOS reached.");
528     return usedCount;
529 }
530 
ToString() const531 std::string DataPacker::ToString() const
532 {
533     return "DataPacker (offset " + std::to_string(mediaOffset_) + ", size " + std::to_string(size_) +
534         ", buffer count " + std::to_string(que_.size()) + ")";
535 }
536 } // namespace Media
537 } // namespace OHOS
538