1 /* 2 * Copyright (c) 2024-2024 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 16 #ifndef HISTREAMER_CACHED_MEDIA_BUFFER_H 17 #define HISTREAMER_CACHED_MEDIA_BUFFER_H 18 19 #include <cstdint> 20 #include <memory> 21 #include <mutex> 22 #include <list> 23 #include <chrono> 24 25 #include "common/log.h" 26 #include "lru_cache.h" 27 28 namespace OHOS { 29 namespace Media { 30 constexpr uint32_t CHUNK_SIZE = 16 * 1024; 31 constexpr uint64_t MAX_CACHE_BUFFER_SIZE = 19 * 1024 * 1024; 32 33 using Clock = std::chrono::steady_clock; 34 using TimePoint = Clock::time_point; 35 using namespace std::chrono; 36 37 struct CacheChunk { 38 uint32_t chunkSize; 39 uint32_t dataLength; 40 uint64_t offset; 41 uint8_t data[]; 42 }; 43 44 using CacheChunkList = std::list<CacheChunk*>; 45 using ChunkIterator = CacheChunkList::iterator; 46 47 struct FragmentCacheBuffer { 48 uint64_t offsetBegin; 49 int64_t dataLength; 50 int64_t accessLength; 51 uint64_t totalReadSize; 52 TimePoint readTime; 53 CacheChunkList chunks; 54 ChunkIterator accessPos; 55 bool isSplit {false}; 56 57 explicit FragmentCacheBuffer(uint64_t offset = 0) : offsetBegin(offset), dataLength(0), 58 accessLength(0), totalReadSize(0), readTime(Clock::now()) 59 { 60 accessPos = chunks.end(); 61 } 62 ~FragmentCacheBufferFragmentCacheBuffer63 ~FragmentCacheBuffer() 64 { 65 chunks.clear(); 66 } 67 }; 68 69 using FragmentCacheBufferList = std::list<FragmentCacheBuffer>; 70 using FragmentIterator = FragmentCacheBufferList::iterator; 71 72 class CacheMediaChunkBufferImpl { 73 public: 74 CacheMediaChunkBufferImpl(); 75 virtual ~CacheMediaChunkBufferImpl(); 76 77 CacheMediaChunkBufferImpl(const CacheMediaChunkBufferImpl&) = delete; 78 CacheMediaChunkBufferImpl(CacheMediaChunkBufferImpl&&) = delete; 79 const CacheMediaChunkBufferImpl& operator=(const CacheMediaChunkBufferImpl&) = delete; 80 CacheMediaChunkBufferImpl& operator=(CacheMediaChunkBufferImpl&&) = delete; 81 82 bool Init(uint64_t totalBuffSize, uint32_t chunkSize); 83 size_t Read(void* ptr, uint64_t offset, size_t readSize); 84 size_t Write(void* ptr, uint64_t inOffset, size_t inWriteSize); 85 bool Seek(uint64_t offset); 86 size_t GetBufferSize(uint64_t offset); 87 uint64_t GetNextBufferOffset(uint64_t offset); 88 void Dump(uint64_t param); 89 bool Check(); 90 void Clear(); 91 uint64_t GetFreeSize(); 92 bool ClearFragmentBeforeOffset(uint64_t offset); 93 bool ClearChunksOfFragment(uint64_t offset); 94 bool ClearMiddleReadFragment(uint64_t minOffset, uint64_t maxOffset); 95 bool IsReadSplit(uint64_t offset); 96 void SetIsLargeOffsetSpan(bool isLargeOffsetSpan); 97 98 protected: 99 virtual CacheChunk* GetFreeCacheChunk(uint64_t offset, bool checkAllowFailContinue = false); 100 virtual ChunkIterator AddFragmentCacheBuffer(uint64_t offset); 101 FragmentIterator GetFragmentIterator(FragmentIterator& currFragmentIter, 102 uint64_t offset, ChunkIterator chunkPos, CacheChunk* splitHead, CacheChunk*& chunkInfo); 103 virtual ChunkIterator SplitFragmentCacheBuffer(FragmentIterator& currFragmentIter, 104 uint64_t offset, ChunkIterator chunkPos); 105 void DeleteHasReadFragmentCacheBuffer(FragmentIterator& fragmentIter, size_t allowChunkNum); 106 FragmentIterator EraseFragmentCache(const FragmentIterator& iter); 107 FragmentIterator GetOffsetFragmentCache(FragmentIterator& fragmentPos, uint64_t offset); 108 ChunkIterator GetOffsetChunkCache(CacheChunkList& fragmentCacheBuffer, uint64_t offset); 109 void DumpInner(uint64_t param); 110 bool CheckInner(); 111 void CheckFragment(const FragmentCacheBuffer& fragment, bool& checkSuccess); 112 bool DumpAndCheckInner(); 113 static void UpdateAccessPos(FragmentIterator& fragmentPos, ChunkIterator& chunkPos, uint64_t offsetChunk); 114 bool WriteInPlace(FragmentIterator& fragmentPos, uint8_t* ptr, uint64_t inOffset, 115 size_t inWriteSize, size_t& outWriteSize); 116 bool WriteMergerPre(uint64_t offset, size_t writeSize, FragmentIterator& nextFragmentPos); 117 void WriteMergerPost(FragmentIterator& nextFragmentPos); 118 size_t ReadInner(void* ptr, uint64_t offset, size_t readSize); 119 120 template<typename Pred> 121 // Search for the fragment pointed to by the offset. GetOffsetFragmentCache(FragmentIterator & fragmentPos,uint64_t offset,Pred pred)122 FragmentIterator GetOffsetFragmentCache(FragmentIterator& fragmentPos, uint64_t offset, Pred pred) 123 { 124 if (fragmentPos != fragmentCacheBuffer_.end()) { 125 if (pred(offset, fragmentPos->offsetBegin, fragmentPos->offsetBegin + fragmentPos->dataLength)) { 126 return fragmentPos; 127 } 128 } 129 130 auto fragmentCachePos = std::find_if(fragmentCacheBuffer_.begin(), fragmentCacheBuffer_.end(), 131 [offset, pred](const auto& fragment) { 132 if (pred(offset, fragment.offsetBegin, fragment.offsetBegin + fragment.dataLength)) { 133 return true; 134 } 135 return false; 136 }); 137 return fragmentCachePos; 138 } 139 140 template<typename Pred> 141 // Search for the chunk pointed to by the offset. GetOffsetChunkCache(CacheChunkList & chunkCaches,uint64_t offset,Pred pred)142 static ChunkIterator GetOffsetChunkCache(CacheChunkList& chunkCaches, uint64_t offset, Pred pred) 143 { 144 auto chunkCachePos = std::find_if(chunkCaches.begin(), chunkCaches.end(), 145 [offset, pred](const auto& fragment) { 146 if (pred(offset, fragment->offset, fragment->offset + fragment->dataLength)) { 147 return true; 148 } 149 return false; 150 }); 151 return chunkCachePos; 152 } 153 154 size_t WriteChunk(FragmentCacheBuffer& fragmentCacheBuffer, ChunkIterator& chunkPos, 155 void* ptr, uint64_t offset, size_t writeSize); 156 bool CheckThresholdFragmentCacheBuffer(FragmentIterator& currWritePos); 157 void DeleteUnreadFragmentCacheBuffer(FragmentIterator& fragmentIter, size_t allowChunkNum); CalcAllowMaxChunkNum(uint64_t fragmentReadSize,uint64_t offset)158 size_t CalcAllowMaxChunkNum(uint64_t fragmentReadSize, uint64_t offset) 159 { 160 size_t allowNum = static_cast<size_t>((static_cast<double>(fragmentReadSize) / 161 static_cast<double>(totalReadSize_)) * chunkMaxNum_); 162 return allowNum; 163 } 164 void ResetReadSizeAlloc(); 165 CacheChunk* UpdateFragmentCacheForDelHead(FragmentIterator& fragmentIter); 166 void HandleFragmentPos(FragmentIterator& fragmentIter); 167 168 protected: 169 std::mutex mutex_; 170 FragmentIterator readPos_; 171 FragmentIterator writePos_; 172 uint64_t totalBuffSize_ {0}; 173 uint64_t totalReadSize_ {0}; 174 uint32_t chunkMaxNum_ {0}; 175 uint32_t chunkSize_ {0}; 176 double initReadSizeFactor_ {0.0}; 177 uint8_t* bufferAddr_ {nullptr}; 178 FragmentCacheBufferList fragmentCacheBuffer_; 179 CacheChunkList freeChunks_; 180 size_t fragmentMaxNum_; 181 LruCache<int64_t, FragmentIterator> lruCache_; 182 bool isLargeOffsetSpan_ {false}; 183 }; 184 185 class CacheMediaBuffer { 186 public: 187 CacheMediaBuffer() = default; 188 virtual ~CacheMediaBuffer() = default; 189 190 virtual bool Init(uint64_t totalBuffSize, uint32_t chunkSize) = 0; 191 virtual size_t Read(void* ptr, uint64_t offset, size_t readSize) = 0; 192 virtual size_t Write(void* ptr, uint64_t offset, size_t writeSize) = 0; 193 virtual bool Seek(uint64_t offset) = 0; 194 virtual size_t GetBufferSize(uint64_t offset) = 0; 195 virtual uint64_t GetNextBufferOffset(uint64_t offset) = 0; 196 virtual void Clear() = 0; 197 virtual void SetReadBlocking(bool isReadBlockingAllowed) = 0; 198 virtual void Dump(uint64_t param) = 0; 199 virtual uint64_t GetFreeSize() = 0; 200 virtual bool ClearFragmentBeforeOffset(uint64_t offset) = 0; 201 virtual bool ClearChunksOfFragment(uint64_t offset) = 0; 202 virtual bool ClearMiddleReadFragment(uint64_t minOffset, uint64_t maxOffset) = 0; 203 virtual bool IsReadSplit(uint64_t offset) = 0; 204 virtual void SetIsLargeOffsetSpan(bool isLargeOffsetSpan) = 0; 205 }; 206 207 class CacheMediaChunkBufferImpl; 208 class CacheMediaChunkBuffer : public CacheMediaBuffer { 209 public: 210 CacheMediaChunkBuffer(); 211 ~CacheMediaChunkBuffer() override; 212 CacheMediaChunkBuffer(const CacheMediaChunkBuffer&) = delete; 213 CacheMediaChunkBuffer(CacheMediaChunkBuffer&&) = delete; 214 const CacheMediaChunkBuffer& operator=(const CacheMediaChunkBuffer&) = delete; 215 CacheMediaChunkBuffer& operator=(CacheMediaChunkBuffer&&) = delete; 216 217 bool Init(uint64_t totalBuffSize, uint32_t chunkSize) override; 218 size_t Read(void* ptr, uint64_t offset, size_t readSize) override; 219 size_t Write(void* ptr, uint64_t offset, size_t writeSize) override; 220 bool Seek(uint64_t offset) override; 221 size_t GetBufferSize(uint64_t offset) override; 222 uint64_t GetNextBufferOffset(uint64_t offset) override; 223 void Clear() override; 224 void SetReadBlocking(bool isReadBlockingAllowed) override; 225 void Dump(uint64_t param) override; 226 bool Check(); 227 uint64_t GetFreeSize() override; 228 bool ClearFragmentBeforeOffset(uint64_t offset) override; 229 bool ClearChunksOfFragment(uint64_t offset) override; 230 bool ClearMiddleReadFragment(uint64_t minOffset, uint64_t maxOffset) override; 231 bool IsReadSplit(uint64_t offset) override; 232 void SetIsLargeOffsetSpan(bool isLargeOffsetSpan) override; 233 private: 234 std::unique_ptr<CacheMediaChunkBufferImpl> impl_; 235 }; 236 237 class CacheMediaChunkBufferHlsImpl : public CacheMediaChunkBufferImpl { 238 protected: 239 CacheChunk* GetFreeCacheChunk(uint64_t offset, bool checkAllowFailContinue = false) override; 240 ChunkIterator SplitFragmentCacheBuffer(FragmentIterator& currFragmentIter, uint64_t offset, 241 ChunkIterator chunkPos) override; 242 ChunkIterator AddFragmentCacheBuffer(uint64_t offset) override; 243 }; 244 245 } 246 } 247 #endif