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 #define HST_LOG_TAG "DashSegmentDownloader"
16
17 #include "dash_segment_downloader.h"
18 #include <map>
19 #include <algorithm>
20 #include "network/network_typs.h"
21 #include "dash_mpd_util.h"
22 #include "avcodec_log.h"
23
24 namespace OHOS {
25 namespace Media {
26 namespace Plugins {
27 namespace HttpPlugin {
28 constexpr uint32_t VID_RING_BUFFER_SIZE = 20 * 1024 * 1024;
29 constexpr uint32_t AUD_RING_BUFFER_SIZE = 2 * 1024 * 1024;
30 constexpr uint32_t SUBTITLE_RING_BUFFER_SIZE = 1 * 1024 * 1024;
31 constexpr uint32_t DEFAULT_RING_BUFFER_SIZE = 5 * 1024 * 1024;
32 constexpr int DEFAULT_WAIT_TIME = 2;
33 constexpr int32_t HTTP_TIME_OUT_MS = 10 * 1000;
34 constexpr uint32_t RECORD_TIME_INTERVAL = 1000;
35 constexpr int32_t RECORD_DOWNLOAD_MIN_BIT = 1000;
36 constexpr uint32_t SPEED_MULTI_FACT = 1000;
37 constexpr uint32_t BYTE_TO_BIT = 8;
38 constexpr int PLAY_WATER_LINE = 5 * 1024;
39 constexpr int64_t BYTES_TO_BIT = 8;
40 constexpr int32_t DEFAULT_VIDEO_WATER_LINE = 512 * 1024;
41 constexpr int32_t DEFAULT_AUDIO_WATER_LINE = 96 * 1024;
42 constexpr float DEFAULT_MIN_CACHE_TIME = 0.3;
43 constexpr float DEFAULT_MAX_CACHE_TIME = 10.0;
44 constexpr uint32_t DURATION_CHANGE_AMOUT_MILLIONSECOND = 500;
45 constexpr int64_t SECOND_TO_MILLISECONDS = 1000;
46 constexpr uint32_t BUFFERING_SLEEP_TIME_MS = 10;
47 constexpr uint32_t BUFFERING_TIME_OUT_MS = 1000;
48 constexpr uint32_t UPDATE_CACHE_STEP = 10;
49 constexpr double ZERO_THRESHOLD = 1e-9;
50 constexpr size_t MAX_BUFFERING_TIME_OUT = 30 * 1000;
51 constexpr size_t DOWNLOADER_RESUME_THRESHOLD = 10 * 1024 * 1024;
52
53 static const std::map<MediaAVCodec::MediaType, uint32_t> BUFFER_SIZE_MAP = {
54 {MediaAVCodec::MediaType::MEDIA_TYPE_VID, VID_RING_BUFFER_SIZE},
55 {MediaAVCodec::MediaType::MEDIA_TYPE_AUD, AUD_RING_BUFFER_SIZE},
56 {MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE, SUBTITLE_RING_BUFFER_SIZE}};
57
DashSegmentDownloader(Callback * callback,int streamId,MediaAVCodec::MediaType streamType,uint64_t expectDuration,std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)58 DashSegmentDownloader::DashSegmentDownloader(Callback *callback, int streamId, MediaAVCodec::MediaType streamType,
59 uint64_t expectDuration, std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)
60 {
61 callback_ = callback;
62 streamId_ = streamId;
63 streamType_ = streamType;
64 expectDuration_ = expectDuration;
65 if (expectDuration_ > 0) {
66 userDefinedBufferDuration_ = true;
67 }
68 size_t ringBufferSize = GetRingBufferInitSize(streamType_);
69 MEDIA_LOG_I("DashSegmentDownloader streamId:" PUBLIC_LOG_D32 ", ringBufferSize:"
70 PUBLIC_LOG_ZU, streamId, ringBufferSize);
71 ringBufferCapcity_ = ringBufferSize;
72 waterLineAbove_ = PLAY_WATER_LINE;
73 buffer_ = std::make_shared<RingBuffer>(ringBufferSize);
74 buffer_->Init();
75
76 sourceLoader_ = sourceLoader;
77 downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
78
79 dataSave_ = [this] (uint8_t*&& data, uint32_t&& len, bool&& notBlock) {
80 return SaveData(std::forward<decltype(data)>(data), std::forward<decltype(len)>(len),
81 std::forward<decltype(notBlock)>(notBlock));
82 };
83
84 downloadRequest_ = nullptr;
85 mediaSegment_ = nullptr;
86 loopInterruptClock_.Reset();
87 recordData_ = std::make_shared<RecordData>();
88 }
89
~DashSegmentDownloader()90 DashSegmentDownloader::~DashSegmentDownloader() noexcept
91 {
92 if (buffer_ != nullptr) {
93 buffer_->SetActive(false, true);
94 }
95 if (downloader_ != nullptr) {
96 downloader_->Stop(false);
97 }
98 segmentList_.clear();
99 }
100
Open(const std::shared_ptr<DashSegment> & dashSegment)101 bool DashSegmentDownloader::Open(const std::shared_ptr<DashSegment>& dashSegment)
102 {
103 std::lock_guard<std::mutex> lock(segmentMutex_);
104 steadyClock_.Reset();
105 lastCheckTime_ = 0;
106 downloadDuringTime_ = 0;
107 totalDownloadDuringTime_ = 0;
108 downloadBits_ = 0;
109 totalBits_ = 0;
110 lastBits_ = 0;
111 mediaSegment_ = std::make_shared<DashBufferSegment>(dashSegment);
112 if (mediaSegment_->byteRange_.length() > 0) {
113 DashParseRange(mediaSegment_->byteRange_, mediaSegment_->startRangeValue_, mediaSegment_->endRangeValue_);
114 }
115
116 if (mediaSegment_->startRangeValue_ >= 0 && mediaSegment_->endRangeValue_ > mediaSegment_->startRangeValue_) {
117 mediaSegment_->contentLength_ = static_cast<size_t>(mediaSegment_->endRangeValue_ -
118 mediaSegment_->startRangeValue_ + 1);
119 }
120 segmentList_.push_back(mediaSegment_);
121 MEDIA_LOG_I("Open enter streamId:" PUBLIC_LOG_D32 " ,seqNum:" PUBLIC_LOG_D64 ", range=" PUBLIC_LOG_D64 "-"
122 PUBLIC_LOG_D64, mediaSegment_->streamId_, mediaSegment_->numberSeq_,
123 mediaSegment_->startRangeValue_, mediaSegment_->endRangeValue_);
124
125 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
126 if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_UNUSE) {
127 MEDIA_LOG_I("Open streamId:" PUBLIC_LOG_D32 ", writeState:"
128 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
129 initSegment->writeState_ = INIT_SEGMENT_STATE_USING;
130 if (!initSegment->isDownloadFinish_) {
131 int64_t startPos = initSegment->rangeBegin_;
132 int64_t endPos = initSegment->rangeEnd_;
133 PutRequestIntoDownloader(0, startPos, endPos, initSegment->url_);
134 } else {
135 initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
136 PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
137 mediaSegment_->endRangeValue_, mediaSegment_->url_);
138 }
139 } else {
140 PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
141 mediaSegment_->endRangeValue_, mediaSegment_->url_);
142 }
143
144 return true;
145 }
146
Close(bool isAsync,bool isClean)147 void DashSegmentDownloader::Close(bool isAsync, bool isClean)
148 {
149 MEDIA_LOG_I("Close enter");
150 buffer_->SetActive(false, isClean);
151 downloader_->Stop(isAsync);
152
153 if (downloadRequest_ != nullptr && !downloadRequest_->IsClosed()) {
154 downloadRequest_->Close();
155 }
156 }
157
Pause()158 void DashSegmentDownloader::Pause()
159 {
160 MEDIA_LOG_I("Pause enter");
161 buffer_->SetActive(false);
162 downloader_->Pause();
163 }
164
Resume()165 void DashSegmentDownloader::Resume()
166 {
167 MEDIA_LOG_I("Resume enter");
168 buffer_->SetActive(true);
169 downloader_->Resume();
170 }
171
Read(uint8_t * buff,ReadDataInfo & readDataInfo,const std::atomic<bool> & isInterruptNeeded)172 DashReadRet DashSegmentDownloader::Read(uint8_t *buff, ReadDataInfo &readDataInfo,
173 const std::atomic<bool> &isInterruptNeeded)
174 {
175 FALSE_RETURN_V_MSG(buffer_ != nullptr, DASH_READ_FAILED, "buffer is null");
176 FALSE_RETURN_V_MSG(!isInterruptNeeded.load(), DASH_READ_INTERRUPT, "isInterruptNeeded");
177 int32_t streamId = readDataInfo.streamId_;
178 uint32_t wantReadLength = readDataInfo.wantReadLength_;
179 uint32_t &realReadLength = readDataInfo.realReadLength_;
180 int32_t &realStreamId = readDataInfo.nextStreamId_;
181 FALSE_RETURN_V_MSG(readDataInfo.wantReadLength_ > 0, DASH_READ_FAILED, "wantReadLength_ <= 0");
182
183 DashReadRet readRet = DASH_READ_OK;
184 if (CheckReadInterrupt(realReadLength, wantReadLength, readRet, isInterruptNeeded)) {
185 return readRet;
186 }
187
188 std::shared_ptr<DashBufferSegment> currentSegment = GetCurrentSegment();
189 int32_t currentStreamId = streamId;
190 if (currentSegment != nullptr) {
191 currentStreamId = currentSegment->streamId_;
192 }
193 realStreamId = currentStreamId;
194 if (realStreamId != streamId) {
195 MEDIA_LOG_I("Read: changed stream streamId:" PUBLIC_LOG_D32 ", realStreamId:"
196 PUBLIC_LOG_D32, streamId, realStreamId);
197 UpdateInitSegmentState(currentStreamId);
198 return readRet;
199 }
200
201 if (ReadInitSegment(buff, wantReadLength, realReadLength, currentStreamId)) {
202 return DASH_READ_OK;
203 }
204 bool canWriteTmp = canWrite_.load();
205 uint32_t maxReadLength = GetMaxReadLength(wantReadLength, currentSegment, currentStreamId);
206 realReadLength = buffer_->ReadBuffer(buff, maxReadLength, DEFAULT_WAIT_TIME);
207 size_t bufferSize = buffer_->GetSize();
208 if (downloader_ != nullptr && sourceLoader_ != nullptr && !canWriteTmp && realReadLength > 0
209 && bufferSize < DOWNLOADER_RESUME_THRESHOLD) {
210 downloader_->Resume();
211 MEDIA_LOG_D("Dash downloader resume.");
212 }
213 if (realReadLength == 0) {
214 MEDIA_LOG_W("After read: streamId:" PUBLIC_LOG_D32 " ,bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
215 ", realReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(),
216 realReadLength);
217 return DASH_READ_AGAIN;
218 }
219
220 MEDIA_LOG_D("After read: streamId:" PUBLIC_LOG_D32 " ,bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
221 ", realReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(),
222 realReadLength);
223 ClearReadSegmentList();
224 return readRet;
225 }
226
GetMaxReadLength(uint32_t wantReadLength,const std::shared_ptr<DashBufferSegment> & currentSegment,int32_t currentStreamId) const227 uint32_t DashSegmentDownloader::GetMaxReadLength(uint32_t wantReadLength,
228 const std::shared_ptr<DashBufferSegment> ¤tSegment,
229 int32_t currentStreamId) const
230 {
231 uint32_t maxReadLength = wantReadLength;
232 if (currentSegment != nullptr) {
233 uint32_t availableSize = currentSegment->bufferPosTail_ - buffer_->GetHead();
234 if (availableSize > 0) {
235 maxReadLength = availableSize;
236 }
237 }
238 maxReadLength = maxReadLength > wantReadLength ? wantReadLength : maxReadLength;
239 MEDIA_LOG_D("Read: streamId:" PUBLIC_LOG_D32 " limit, bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
240 ", maxReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(), maxReadLength);
241 return maxReadLength;
242 }
243
IsSegmentFinished(uint32_t & realReadLength,DashReadRet & readRet)244 bool DashSegmentDownloader::IsSegmentFinished(uint32_t &realReadLength, DashReadRet &readRet)
245 {
246 if (isAllSegmentFinished_.load()) {
247 readRet = DASH_READ_SEGMENT_DOWNLOAD_FINISH;
248 if (buffer_->GetSize() == 0) {
249 readRet = DASH_READ_END;
250 realReadLength = 0;
251 if (mediaSegment_ != nullptr) {
252 MEDIA_LOG_I("Read: streamId:" PUBLIC_LOG_D32 " segment "
253 PUBLIC_LOG_D64 " read Eos", mediaSegment_->streamId_, mediaSegment_->numberSeq_);
254 }
255 DoBufferingEndEvent();
256 return true;
257 }
258 }
259 return false;
260 }
261
CheckReadInterrupt(uint32_t & realReadLength,uint32_t wantReadLength,DashReadRet & readRet,const std::atomic<bool> & isInterruptNeeded)262 bool DashSegmentDownloader::CheckReadInterrupt(uint32_t &realReadLength, uint32_t wantReadLength, DashReadRet &readRet,
263 const std::atomic<bool> &isInterruptNeeded)
264 {
265 if (IsSegmentFinished(realReadLength, readRet)) {
266 return true;
267 }
268
269 if (HandleBuffering(isInterruptNeeded)) {
270 MEDIA_LOG_E("DashSegmentDownloader read return error again streamId: " PUBLIC_LOG_D32, streamId_);
271 readRet = DASH_READ_AGAIN;
272 return true;
273 }
274
275 bool arrivedBuffering = streamType_ != MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE && isFirstFrameArrived_ &&
276 buffer_->GetSize() < static_cast<size_t>(PLAY_WATER_LINE);
277 if (arrivedBuffering && !isAllSegmentFinished_.load()) {
278 if (HandleCache()) {
279 readRet = DASH_READ_AGAIN;
280 return true;
281 }
282 }
283
284 if (isInterruptNeeded.load()) {
285 realReadLength = 0;
286 readRet = DASH_READ_INTERRUPT;
287 MEDIA_LOG_I("DashSegmentDownloader interruptNeeded streamId: " PUBLIC_LOG_D32, streamId_);
288 return true;
289 }
290 return false;
291 }
292
HandleBuffering(const std::atomic<bool> & isInterruptNeeded)293 bool DashSegmentDownloader::HandleBuffering(const std::atomic<bool> &isInterruptNeeded)
294 {
295 if (!isBuffering_.load()) {
296 return false;
297 }
298
299 MEDIA_LOG_I("HandleBuffering begin streamId: " PUBLIC_LOG_D32, streamId_);
300 int32_t sleepTime = 0;
301 while (!isInterruptNeeded.load()) {
302 if (!isBuffering_.load()) {
303 break;
304 }
305
306 if (isAllSegmentFinished_.load()) {
307 DoBufferingEndEvent();
308 break;
309 }
310 OSAL::SleepFor(BUFFERING_SLEEP_TIME_MS);
311 sleepTime += BUFFERING_SLEEP_TIME_MS;
312 if (sleepTime > BUFFERING_TIME_OUT_MS) {
313 break;
314 }
315 }
316 MEDIA_LOG_I("HandleBuffering end streamId: " PUBLIC_LOG_D32 " isBuffering: "
317 PUBLIC_LOG_D32, streamId_, isBuffering_.load());
318 return isBuffering_.load();
319 }
320
SaveDataHandleBuffering()321 void DashSegmentDownloader::SaveDataHandleBuffering()
322 {
323 if (IsNeedBufferForPlaying() || !isBuffering_.load()) {
324 return;
325 }
326 UpdateCachedPercent(BufferingInfoType::BUFFERING_PERCENT);
327 if (buffer_->GetSize() >= waterLineAbove_ || isAllSegmentFinished_.load()) {
328 DoBufferingEndEvent();
329 }
330 }
331
DoBufferingEndEvent()332 void DashSegmentDownloader::DoBufferingEndEvent()
333 {
334 if (isBuffering_.exchange(false)) {
335 MEDIA_LOG_I("DoBufferingEndEvent OnEvent streamId: " PUBLIC_LOG_D32 " cacheData buffering end", streamId_);
336 UpdateCachedPercent(BufferingInfoType::BUFFERING_END);
337 }
338 }
339
HandleCache()340 bool DashSegmentDownloader::HandleCache()
341 {
342 waterLineAbove_ = static_cast<size_t>(GetWaterLineAbove());
343 if (!isBuffering_.exchange(true)) {
344 MEDIA_LOG_I("HandleCache OnEvent streamId: " PUBLIC_LOG_D32 " start buffering, waterLineAbove:"
345 PUBLIC_LOG_U32, streamId_, waterLineAbove_);
346 UpdateCachedPercent(BufferingInfoType::BUFFERING_START);
347 return true;
348 }
349 return false;
350 }
351
GetWaterLineAbove()352 int32_t DashSegmentDownloader::GetWaterLineAbove()
353 {
354 int32_t waterLineAbove = streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID ? DEFAULT_VIDEO_WATER_LINE :
355 DEFAULT_AUDIO_WATER_LINE;
356 if (downloadRequest_ != nullptr && realTimeBitBate_ > 0) {
357 MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " realTimeBitBate: "
358 PUBLIC_LOG_D64 " downloadBiteRate: " PUBLIC_LOG_U32, streamId_, realTimeBitBate_, downloadBiteRate_);
359 if (downloadBiteRate_ == 0) {
360 MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " use default waterLineAbove: "
361 PUBLIC_LOG_D32, streamId_, waterLineAbove);
362 return waterLineAbove;
363 }
364
365 if (realTimeBitBate_ > static_cast<int64_t>(downloadBiteRate_)) {
366 waterLineAbove = static_cast<int32_t>(DEFAULT_MAX_CACHE_TIME * realTimeBitBate_ / BYTES_TO_BIT);
367 } else {
368 waterLineAbove = static_cast<int32_t>(DEFAULT_MIN_CACHE_TIME * realTimeBitBate_ / BYTES_TO_BIT);
369 }
370 int32_t maxWaterLineAbove = static_cast<int32_t>(ringBufferCapcity_ / 2);
371 waterLineAbove = waterLineAbove > maxWaterLineAbove ? maxWaterLineAbove : waterLineAbove;
372 int32_t minWaterLineAbove = 2 * PLAY_WATER_LINE;
373 waterLineAbove = waterLineAbove < minWaterLineAbove ? minWaterLineAbove : waterLineAbove;
374 }
375 MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " waterLineAbove: "
376 PUBLIC_LOG_D32, streamId_, waterLineAbove);
377 return waterLineAbove;
378 }
379
CalculateBitRate(size_t fragmentSize,double duration)380 void DashSegmentDownloader::CalculateBitRate(size_t fragmentSize, double duration)
381 {
382 if (fragmentSize == 0 || duration == 0) {
383 return;
384 }
385
386 realTimeBitBate_ = static_cast<int64_t>(fragmentSize * BYTES_TO_BIT * SECOND_TO_MILLISECONDS) / duration;
387 MEDIA_LOG_I("CalculateBitRate streamId: " PUBLIC_LOG_D32 " realTimeBitBate: "
388 PUBLIC_LOG_D64, streamId_, realTimeBitBate_);
389 }
390
HandleCachedDuration()391 void DashSegmentDownloader::HandleCachedDuration()
392 {
393 auto tmpBitRate = realTimeBitBate_;
394 if (tmpBitRate <= 0) {
395 return;
396 }
397
398 uint64_t cachedDuration = static_cast<uint64_t>((static_cast<int64_t>(buffer_->GetSize()) *
399 BYTES_TO_BIT * SECOND_TO_MILLISECONDS) / tmpBitRate);
400 if ((cachedDuration > lastDurationRecord_ &&
401 cachedDuration - lastDurationRecord_ > DURATION_CHANGE_AMOUT_MILLIONSECOND) ||
402 (lastDurationRecord_ > cachedDuration &&
403 lastDurationRecord_ - cachedDuration > DURATION_CHANGE_AMOUT_MILLIONSECOND)) {
404 if (callback_ != nullptr) {
405 MEDIA_LOG_D("HandleCachedDuration OnEvent streamId: " PUBLIC_LOG_D32 " cachedDuration: "
406 PUBLIC_LOG_U64, streamId_, cachedDuration);
407 callback_->OnEvent({PluginEventType::CACHED_DURATION, {cachedDuration}, "buffering_duration"});
408 }
409 lastDurationRecord_ = cachedDuration;
410 }
411 }
412
GetCachedPercent()413 uint32_t DashSegmentDownloader::GetCachedPercent()
414 {
415 if (waterLineAbove_ == 0) {
416 return 0;
417 }
418
419 uint32_t bufferSize = static_cast<uint32_t>(buffer_->GetSize());
420 return (bufferSize >= waterLineAbove_) ? BUFFERING_PERCENT_FULL : bufferSize * BUFFERING_PERCENT_FULL /
421 waterLineAbove_;
422 }
423
UpdateCachedPercent(BufferingInfoType infoType)424 void DashSegmentDownloader::UpdateCachedPercent(BufferingInfoType infoType)
425 {
426 if (waterLineAbove_ == 0 || bufferingCbFunc_ == nullptr) {
427 MEDIA_LOG_W("OnEvent streamId: " PUBLIC_LOG_D32 " UpdateCachedPercent error", streamId_);
428 return;
429 }
430
431 if (infoType == BufferingInfoType::BUFFERING_START || infoType == BufferingInfoType::BUFFERING_END) {
432 lastCachedSize_ = 0;
433 bufferingCbFunc_(streamId_, infoType);
434 return;
435 }
436 if (infoType != BufferingInfoType::BUFFERING_PERCENT) {
437 return;
438 }
439
440 uint32_t bufferSize = static_cast<uint32_t>(buffer_->GetSize());
441 if (bufferSize < lastCachedSize_) {
442 return;
443 }
444 uint32_t deltaSize = bufferSize - lastCachedSize_;
445 if ((deltaSize * BUFFERING_PERCENT_FULL / waterLineAbove_) >= UPDATE_CACHE_STEP) {
446 bufferingCbFunc_(streamId_, infoType);
447 lastCachedSize_ = bufferSize;
448 }
449 }
450
GetCurrentSegment()451 std::shared_ptr<DashBufferSegment> DashSegmentDownloader::GetCurrentSegment()
452 {
453 std::shared_ptr<DashBufferSegment> currentSegment;
454 {
455 std::lock_guard<std::mutex> lock(segmentMutex_);
456 auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
457 [this](const std::shared_ptr<DashBufferSegment> &item) -> bool {
458 return buffer_->GetHead() >= item->bufferPosHead_ && buffer_->GetHead() < item->bufferPosTail_;
459 });
460 if (it != segmentList_.end()) {
461 currentSegment = *it;
462 }
463 }
464 return currentSegment;
465 }
466
UpdateInitSegmentState(int32_t currentStreamId)467 void DashSegmentDownloader::UpdateInitSegmentState(int32_t currentStreamId)
468 {
469 std::lock_guard<std::mutex> lock(initSegmentMutex_);
470 for (auto it = initSegments_.begin(); it != initSegments_.end(); ++it) {
471 if ((*it)->streamId_ == currentStreamId) {
472 MEDIA_LOG_I("UpdateInitSegmentState: init streamId:" PUBLIC_LOG_D32 ", contentLen:"
473 PUBLIC_LOG_ZU ", readIndex:" PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
474 PUBLIC_LOG_D32, currentStreamId, (*it)->content_.length(), (*it)->readIndex_,
475 (*it)->isDownloadFinish_, (*it)->readState_);
476 }
477 (*it)->readIndex_ = 0;
478 (*it)->readState_ = INIT_SEGMENT_STATE_UNUSE;
479 }
480 }
481
ReadInitSegment(uint8_t * buff,uint32_t wantReadLength,uint32_t & realReadLength,int32_t currentStreamId)482 bool DashSegmentDownloader::ReadInitSegment(uint8_t *buff, uint32_t wantReadLength, uint32_t &realReadLength,
483 int32_t currentStreamId)
484 {
485 std::lock_guard<std::mutex> lock(initSegmentMutex_);
486 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(currentStreamId);
487 if (initSegment != nullptr && initSegment->readState_ != INIT_SEGMENT_STATE_USED) {
488 unsigned int contentLen = initSegment->content_.length();
489 MEDIA_LOG_I("Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex:"
490 PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
491 PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
492 initSegment->isDownloadFinish_, initSegment->readState_);
493 if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
494 // init segment read finish
495 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
496 initSegment->readIndex_ = 0;
497 return true;
498 }
499
500 unsigned int unReadSize = contentLen - initSegment->readIndex_;
501 if (unReadSize > 0) {
502 realReadLength = unReadSize > wantReadLength ? wantReadLength : unReadSize;
503 std::string readStr = initSegment->content_.substr(initSegment->readIndex_);
504 CHECK_AND_RETURN_RET_LOG(wantReadLength <= VID_RING_BUFFER_SIZE * BYTE_TO_BIT, 1, "too large");
505 CHECK_AND_RETURN_RET_LOG(realReadLength <= VID_RING_BUFFER_SIZE * BYTE_TO_BIT, 1, "too large");
506 memcpy_s(buff, wantReadLength, readStr.c_str(), realReadLength);
507 initSegment->readIndex_ += realReadLength;
508 if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
509 // init segment read finish
510 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
511 initSegment->readIndex_ = 0;
512 }
513 }
514
515 MEDIA_LOG_I("after Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex_:"
516 PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
517 initSegment->isDownloadFinish_);
518 return true;
519 }
520 return false;
521 }
522
ClearReadSegmentList()523 void DashSegmentDownloader::ClearReadSegmentList()
524 {
525 std::lock_guard<std::mutex> lock(segmentMutex_);
526 for (auto it = segmentList_.begin(); it != segmentList_.end(); ++it) {
527 if (buffer_->GetHead() != 0 && (*it)->isEos_ && buffer_->GetHead() >= (*it)->bufferPosTail_) {
528 MEDIA_LOG_D("Read:streamId:" PUBLIC_LOG_D32 ", erase numberSeq:"
529 PUBLIC_LOG_D64, (*it)->streamId_, (*it)->numberSeq_);
530 it = segmentList_.erase(it);
531 } else {
532 break;
533 }
534 }
535 }
536
SetStatusCallback(StatusCallbackFunc statusCallbackFunc)537 void DashSegmentDownloader::SetStatusCallback(StatusCallbackFunc statusCallbackFunc)
538 {
539 statusCallback_ = statusCallbackFunc;
540 }
541
SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)542 void DashSegmentDownloader::SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)
543 {
544 downloadDoneCbFunc_ = doneCbFunc;
545 }
546
SetSegmentBufferingCallback(SegmentBufferingCbFunc bufferingCbFunc)547 void DashSegmentDownloader::SetSegmentBufferingCallback(SegmentBufferingCbFunc bufferingCbFunc)
548 {
549 bufferingCbFunc_ = bufferingCbFunc;
550 }
551
GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const552 size_t DashSegmentDownloader::GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const
553 {
554 size_t ringBufferFixSize = DEFAULT_RING_BUFFER_SIZE;
555 auto ringBufferSizeItem = BUFFER_SIZE_MAP.find(streamType);
556 if (ringBufferSizeItem != BUFFER_SIZE_MAP.end()) {
557 ringBufferFixSize = ringBufferSizeItem->second;
558 }
559
560 if (streamType == MediaAVCodec::MediaType::MEDIA_TYPE_VID && userDefinedBufferDuration_) {
561 size_t ringBufferSize = expectDuration_ * currentBitrate_;
562 if (ringBufferSize < DEFAULT_RING_BUFFER_SIZE) {
563 MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already lower than the min buffer size: "
564 PUBLIC_LOG_U32 ", setting buffer size: "
565 PUBLIC_LOG_U32, ringBufferSize, DEFAULT_RING_BUFFER_SIZE, DEFAULT_RING_BUFFER_SIZE);
566 ringBufferSize = DEFAULT_RING_BUFFER_SIZE;
567 } else if (ringBufferSize > ringBufferFixSize) {
568 MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already exceed the max buffer size: "
569 PUBLIC_LOG_ZU ", setting buffer size: "
570 PUBLIC_LOG_ZU, ringBufferSize, ringBufferFixSize, ringBufferFixSize);
571 ringBufferSize = ringBufferFixSize;
572 }
573 return ringBufferSize;
574 } else {
575 return ringBufferFixSize;
576 }
577 }
578
SetInitSegment(std::shared_ptr<DashInitSegment> initSegment,bool needUpdateState)579 void DashSegmentDownloader::SetInitSegment(std::shared_ptr<DashInitSegment> initSegment, bool needUpdateState)
580 {
581 if (initSegment == nullptr) {
582 return;
583 }
584
585 std::lock_guard<std::mutex> lock(initSegmentMutex_);
586 int streamId = initSegment->streamId_;
587 std::shared_ptr<DashInitSegment> dashInitSegment = GetDashInitSegment(streamId);
588 if (dashInitSegment == nullptr) {
589 initSegments_.push_back(initSegment);
590 dashInitSegment = initSegment;
591 needUpdateState = true;
592 }
593
594 if (!dashInitSegment->isDownloadFinish_) {
595 dashInitSegment->writeState_ = INIT_SEGMENT_STATE_UNUSE;
596 }
597
598 // seek or first time to set stream init segment should update to UNUSE
599 // read will update state to UNUSE when stream id is changed
600 if (needUpdateState) {
601 dashInitSegment->readState_ = INIT_SEGMENT_STATE_UNUSE;
602 }
603 MEDIA_LOG_I("SetInitSegment:streamId:" PUBLIC_LOG_D32 ", isDownloadFinish_="
604 PUBLIC_LOG_D32 ", readIndex=" PUBLIC_LOG_U32 ", readState_=" PUBLIC_LOG_D32 ", update="
605 PUBLIC_LOG_D32 ", writeState_=" PUBLIC_LOG_D32, streamId, dashInitSegment->isDownloadFinish_,
606 dashInitSegment->readIndex_, dashInitSegment->readState_, needUpdateState, dashInitSegment->writeState_);
607 }
608
UpdateStreamId(int streamId)609 void DashSegmentDownloader::UpdateStreamId(int streamId)
610 {
611 streamId_ = streamId;
612 }
613
SetCurrentBitRate(int32_t bitRate)614 void DashSegmentDownloader::SetCurrentBitRate(int32_t bitRate)
615 {
616 if (bitRate <= 0) {
617 realTimeBitBate_ = -1;
618 } else {
619 realTimeBitBate_ = static_cast<int64_t>(bitRate);
620 }
621 }
622
SetDemuxerState()623 void DashSegmentDownloader::SetDemuxerState()
624 {
625 isFirstFrameArrived_ = true;
626 }
627
SetAllSegmentFinished()628 void DashSegmentDownloader::SetAllSegmentFinished()
629 {
630 MEDIA_LOG_I("SetAllSegmentFinished streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
631 isAllSegmentFinished_.store(true);
632 }
633
GetStreamId() const634 int DashSegmentDownloader::GetStreamId() const
635 {
636 return streamId_;
637 }
638
GetStreamType() const639 MediaAVCodec::MediaType DashSegmentDownloader::GetStreamType() const
640 {
641 return streamType_;
642 }
643
GetContentLength()644 size_t DashSegmentDownloader::GetContentLength()
645 {
646 if (downloadRequest_ == nullptr || downloadRequest_->IsClosed()) {
647 return 0; // 0
648 }
649 return downloadRequest_->GetFileContentLength();
650 }
651
GetStartedStatus() const652 bool DashSegmentDownloader::GetStartedStatus() const
653 {
654 return startedPlayStatus_;
655 }
656
IsSegmentFinish() const657 bool DashSegmentDownloader::IsSegmentFinish() const
658 {
659 if (mediaSegment_ != nullptr && mediaSegment_->isEos_) {
660 return true;
661 }
662
663 return false;
664 }
665
CleanAllSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)666 bool DashSegmentDownloader::CleanAllSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
667 {
668 if (isCleanAll) {
669 MEDIA_LOG_I("CleanAllSegmentBuffer clean all");
670 isCleaningBuffer_.store(true);
671 Close(false, true);
672 std::lock_guard<std::mutex> lock(segmentMutex_);
673 isAllSegmentFinished_.store(false);
674 for (const auto &it: segmentList_) {
675 if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
676 continue;
677 }
678
679 remainLastNumberSeq = it->numberSeq_;
680 break;
681 }
682
683 downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
684 buffer_->Clear();
685 segmentList_.clear();
686 buffer_->SetActive(true);
687 return true;
688 }
689
690 return false;
691 }
692
CleanSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)693 bool DashSegmentDownloader::CleanSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
694 {
695 if (CleanAllSegmentBuffer(isCleanAll, remainLastNumberSeq)) {
696 return true;
697 }
698
699 size_t clearTail = 0;
700 {
701 std::lock_guard<std::mutex> lock(segmentMutex_);
702 remainLastNumberSeq = -1;
703 uint32_t remainDuration = 0;
704 for (const auto &it: segmentList_) {
705 if (it == nullptr || (buffer_->GetHead() > it->bufferPosTail_ && it->bufferPosTail_ > 0)) {
706 continue;
707 }
708
709 remainLastNumberSeq = it->numberSeq_;
710
711 if (!it->isEos_) {
712 break;
713 }
714
715 remainDuration += GetSegmentRemainDuration(it);
716 if (remainDuration >= MIN_RETENTION_DURATION_MS) {
717 clearTail = it->bufferPosTail_;
718 break;
719 }
720 }
721
722 MEDIA_LOG_I("CleanSegmentBuffer:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
723 PUBLIC_LOG_D64, streamId_, remainLastNumberSeq);
724 }
725
726 if (clearTail > 0) {
727 isCleaningBuffer_.store(true);
728 Close(false, false);
729 std::lock_guard<std::mutex> lock(segmentMutex_);
730 isAllSegmentFinished_.store(false);
731 segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
732 return (bufferSegment->numberSeq_ > remainLastNumberSeq);
733 });
734
735 downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
736 MEDIA_LOG_I("CleanSegmentBuffer bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
737 PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(), clearTail);
738 buffer_->SetTail(clearTail);
739 buffer_->SetActive(true);
740 return true;
741 }
742 return false;
743 }
744
CleanByTimeInternal(int64_t & remainLastNumberSeq,size_t & clearTail,bool & isEnd)745 void DashSegmentDownloader::CleanByTimeInternal(int64_t& remainLastNumberSeq, size_t& clearTail, bool& isEnd)
746 {
747 // residue segment duration
748 uint32_t remainDuration = 0;
749 uint32_t segmentKeepDuration = 1000; // ms
750 uint32_t segmentKeepDelta = 100; // ms
751 for (const auto &it: segmentList_) {
752 if (it == nullptr ||
753 buffer_->GetHead() > it->bufferPosTail_ ||
754 it->bufferPosHead_ >= it->bufferPosTail_) {
755 continue;
756 }
757
758 remainLastNumberSeq = it->numberSeq_;
759 isEnd = it->isEos_;
760 if (it->contentLength_ == 0 ||
761 it->duration_ == 0) {
762 MEDIA_LOG_I("CleanByTimeInternal: contentLength is:" PUBLIC_LOG_ZU ", duration is:"
763 PUBLIC_LOG_U32, it->contentLength_, it->duration_);
764 // can not caculate segment content length, just keep one segment
765 clearTail = it->bufferPosTail_;
766 break;
767 }
768
769 remainDuration = (it->bufferPosTail_ - buffer_->GetHead()) * it->duration_ / it->contentLength_;
770 if (remainDuration < segmentKeepDuration + segmentKeepDelta &&
771 remainDuration + segmentKeepDelta >= segmentKeepDuration) {
772 // find clear buffer position with segment tail position
773 clearTail = it->bufferPosTail_;
774 } else if (remainDuration < segmentKeepDuration) {
775 // get next segment buffer
776 clearTail = it->bufferPosTail_;
777 segmentKeepDuration -= remainDuration;
778 continue;
779 } else {
780 // find clear buffer position
781 uint32_t segmentSize = (segmentKeepDuration * it->contentLength_) / it->duration_;
782 if (clearTail > 0) {
783 // find clear buffer position in multi segments
784 clearTail += segmentSize;
785 } else {
786 // find clear buffer position in one segment
787 clearTail = buffer_->GetHead() + segmentSize;
788 }
789 it->bufferPosTail_ = clearTail;
790 it->isEos_ = true;
791 isEnd = false;
792 }
793
794 break;
795 }
796 }
797
CleanBufferByTime(int64_t & remainLastNumberSeq,bool & isEnd)798 bool DashSegmentDownloader::CleanBufferByTime(int64_t& remainLastNumberSeq, bool& isEnd)
799 {
800 Close(false, false);
801 std::lock_guard<std::mutex> lock(segmentMutex_);
802 remainLastNumberSeq = -1;
803 size_t clearTail = 0;
804 CleanByTimeInternal(remainLastNumberSeq, clearTail, isEnd);
805
806 if (remainLastNumberSeq == -1 && mediaSegment_ != nullptr) {
807 isEnd = false;
808 }
809
810 MEDIA_LOG_I("CleanBufferByTime:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
811 PUBLIC_LOG_D64 ", isEnd:" PUBLIC_LOG_D32 ", size:" PUBLIC_LOG_ZU, streamId_,
812 remainLastNumberSeq, isEnd, segmentList_.size());
813
814 if (clearTail > 0) {
815 isCleaningBuffer_.store(true);
816 segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
817 return (bufferSegment->numberSeq_ > remainLastNumberSeq);
818 });
819
820 downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
821 MEDIA_LOG_I("CleanBufferByTime bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
822 PUBLIC_LOG_ZU " ,seq:" PUBLIC_LOG_D64 ",size:" PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(),
823 clearTail, remainLastNumberSeq, segmentList_.size());
824 buffer_->SetTail(clearTail);
825 buffer_->SetActive(true);
826 return true;
827 }
828 return false;
829 }
830
SeekToTime(const std::shared_ptr<DashSegment> & segment,int32_t & streamId)831 bool DashSegmentDownloader::SeekToTime(const std::shared_ptr<DashSegment> &segment, int32_t& streamId)
832 {
833 std::lock_guard<std::mutex> lock(segmentMutex_);
834 std::shared_ptr<DashBufferSegment> desSegment;
835 auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
836 [&segment](const std::shared_ptr<DashBufferSegment> &item) -> bool {
837 return (item->numberSeq_ - item->startNumberSeq_) == (segment->numberSeq_ - segment->startNumberSeq_);
838 });
839 if (it != segmentList_.end()) {
840 desSegment = *it;
841 }
842
843 if (desSegment != nullptr && desSegment->bufferPosTail_ > 0) {
844 if (buffer_->SetHead(desSegment->bufferPosHead_)) {
845 // set init segment when seek on buffered, before read first segment demuxer plugin need reboot
846 UpdateInitSegmentState(desSegment->streamId_);
847 streamId = desSegment->streamId_;
848 return true;
849 }
850 }
851 return false;
852 }
853
SaveData(uint8_t * data,uint32_t len,bool notBlock)854 uint32_t DashSegmentDownloader::SaveData(uint8_t* data, uint32_t len, bool notBlock)
855 {
856 MEDIA_LOG_D("SaveData:streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
857 size_t freeSize = buffer_->GetFreeSize();
858 startedPlayStatus_ = true;
859 if (notBlock && len >= freeSize) {
860 MEDIA_LOG_D("SaveData buffer not enough, freeSize " PUBLIC_LOG_ZU ", len:" PUBLIC_LOG_U32, freeSize, len);
861 canWrite_.store(false);
862 if (freeSize == 0) {
863 return 0;
864 }
865 len = freeSize;
866 }
867 if (notBlock && len < freeSize) {
868 canWrite_.store(true);
869 }
870 if (streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
871 OnWriteRingBuffer(len);
872 }
873 {
874 std::lock_guard<std::mutex> lock(initSegmentMutex_);
875 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
876 if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
877 MEDIA_LOG_I("SaveData:streamId:" PUBLIC_LOG_D32 ", writeState:"
878 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
879 initSegment->content_.append(reinterpret_cast<const char*>(data), len);
880 return len;
881 }
882 }
883
884 size_t bufferTail = buffer_->GetTail();
885 bool writeRet = buffer_->WriteBuffer(data, len);
886 HandleCachedDuration();
887 SaveDataHandleBuffering();
888 if (!writeRet) {
889 MEDIA_LOG_E("SaveData:error streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
890 return 0;
891 }
892 UpdateMediaSegments(bufferTail, len);
893 return len;
894 }
895
UpdateMediaSegments(size_t bufferTail,uint32_t len)896 void DashSegmentDownloader::UpdateMediaSegments(size_t bufferTail, uint32_t len)
897 {
898 std::lock_guard<std::mutex> lock(segmentMutex_);
899 int64_t loopStartTime = loopInterruptClock_.ElapsedSeconds();
900 for (const auto &mediaSegment: segmentList_) {
901 CheckLoopTimeout(loopStartTime);
902 if (mediaSegment == nullptr || mediaSegment->isEos_) {
903 continue;
904 }
905
906 if (mediaSegment->bufferPosTail_ == 0) {
907 mediaSegment->bufferPosHead_ = bufferTail;
908 }
909 mediaSegment->bufferPosTail_ = buffer_->GetTail();
910 UpdateBufferSegment(mediaSegment, len);
911 break;
912 }
913 }
914
UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> & mediaSegment,uint32_t len)915 void DashSegmentDownloader::UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> &mediaSegment, uint32_t len)
916 {
917 if (mediaSegment->contentLength_ == 0 && downloadRequest_ != nullptr) {
918 mediaSegment->contentLength_ = downloadRequest_->GetFileContentLength();
919 }
920
921 // last packet len is 0 of chunk
922 if (len == 0 || (mediaSegment->contentLength_ > 0 &&
923 mediaSegment->bufferPosTail_ >= (mediaSegment->bufferPosHead_ + mediaSegment->contentLength_))) {
924 mediaSegment->isEos_ = true;
925 if (mediaSegment->isLast_) {
926 MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
927 isAllSegmentFinished_.store(true);
928 }
929 if (mediaSegment->contentLength_ == 0) {
930 mediaSegment->contentLength_ = mediaSegment->bufferPosTail_ - mediaSegment->bufferPosHead_;
931 }
932 MEDIA_LOG_I("SaveData eos:streamId:" PUBLIC_LOG_D32 ", segmentNum:" PUBLIC_LOG_D64 ", contentLength:"
933 PUBLIC_LOG_ZU ", bufferPosHead:" PUBLIC_LOG_ZU " ,bufferPosEnd:" PUBLIC_LOG_ZU,
934 mediaSegment->streamId_, mediaSegment->numberSeq_, mediaSegment->contentLength_,
935 mediaSegment->bufferPosHead_, mediaSegment->bufferPosTail_);
936 }
937 }
938
OnWriteRingBuffer(uint32_t len)939 void DashSegmentDownloader::OnWriteRingBuffer(uint32_t len)
940 {
941 uint32_t writeBits = len * BYTE_TO_BIT;
942 totalBits_ += writeBits;
943 uint64_t now = static_cast<uint64_t>(steadyClock_.ElapsedMilliseconds());
944 if (now > lastCheckTime_ && now - lastCheckTime_ > RECORD_TIME_INTERVAL) {
945 uint64_t curDownloadBits = totalBits_ - lastBits_;
946 if (curDownloadBits >= RECORD_DOWNLOAD_MIN_BIT) {
947 downloadDuringTime_ = now - lastCheckTime_;
948 downloadBits_ += curDownloadBits;
949 totalDownloadDuringTime_ += downloadDuringTime_;
950 double downloadRate = 0;
951 double tmpNumerator = static_cast<double>(curDownloadBits);
952 double tmpDenominator = static_cast<double>(downloadDuringTime_) / SECOND_TO_MILLISECONDS;
953 if (tmpDenominator > ZERO_THRESHOLD) {
954 downloadRate = tmpNumerator / tmpDenominator;
955 }
956 size_t remainingBuffer = 0;
957 if (buffer_ != nullptr) {
958 remainingBuffer = buffer_->GetSize();
959 }
960 MEDIA_LOG_D("Current download speed : " PUBLIC_LOG_D32 " Kbit/s,Current buffer size : " PUBLIC_LOG_U64
961 " KByte", static_cast<int32_t>(downloadRate / 1024), static_cast<uint64_t>(remainingBuffer / 1024));
962 // Remaining playable time: s
963 uint64_t bufferDuration = 0;
964 if (realTimeBitBate_ > 0) {
965 bufferDuration =
966 remainingBuffer * static_cast<uint64_t>(BYTES_TO_BIT) / static_cast<uint64_t>(realTimeBitBate_);
967 } else {
968 bufferDuration = static_cast<uint64_t>(remainingBuffer * BYTES_TO_BIT) / currentBitrate_;
969 }
970 if (recordData_ != nullptr) {
971 recordData_->downloadRate = downloadRate;
972 recordData_->bufferDuring = bufferDuration;
973 }
974 }
975 lastBits_ = totalBits_;
976 lastCheckTime_ = now;
977 }
978 }
979
GetDownloadSpeed() const980 uint64_t DashSegmentDownloader::GetDownloadSpeed() const
981 {
982 return static_cast<uint64_t>(downloadSpeed_);
983 }
984
GetIp(std::string & ip)985 void DashSegmentDownloader::GetIp(std::string& ip)
986 {
987 if (downloader_) {
988 downloader_->GetIp(ip);
989 }
990 }
991
GetDownloadFinishState()992 bool DashSegmentDownloader::GetDownloadFinishState()
993 {
994 std::shared_ptr<DashInitSegment> finishState = GetDashInitSegment(streamId_);
995 if (finishState) {
996 return finishState->isDownloadFinish_;
997 } else {
998 return true;
999 }
1000 }
1001
GetDownloadRecordData()1002 std::pair<int64_t, int64_t> DashSegmentDownloader::GetDownloadRecordData()
1003 {
1004 std::pair<int64_t, int64_t> recordData;
1005 if (recordData_ != nullptr) {
1006 recordData.first = static_cast<int64_t>(recordData_->downloadRate);
1007 recordData.second = static_cast<int64_t>(recordData_->bufferDuring);
1008 } else {
1009 recordData.first = 0;
1010 recordData.second = 0;
1011 }
1012 return recordData;
1013 }
1014
GetBufferSize() const1015 uint32_t DashSegmentDownloader::GetBufferSize() const
1016 {
1017 if (buffer_ != nullptr) {
1018 return buffer_->GetSize();
1019 }
1020 return 0;
1021 }
1022
GetRingBufferCapacity() const1023 uint32_t DashSegmentDownloader::GetRingBufferCapacity() const
1024 {
1025 return ringBufferCapcity_;
1026 }
1027
PutRequestIntoDownloader(unsigned int duration,int64_t startPos,int64_t endPos,const std::string & url)1028 void DashSegmentDownloader::PutRequestIntoDownloader(unsigned int duration, int64_t startPos, int64_t endPos,
1029 const std::string &url)
1030 {
1031 auto realStatusCallback = [this](DownloadStatus &&status, std::shared_ptr<Downloader> &downloader,
1032 std::shared_ptr<DownloadRequest> &request) {
1033 statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
1034 };
1035 auto downloadDoneCallback = [this](const std::string &url, const std::string &location) {
1036 UpdateDownloadFinished(url, location);
1037 };
1038
1039 bool requestWholeFile = true;
1040 if (startPos >= 0 && endPos > 0) {
1041 requestWholeFile = false;
1042 }
1043 RequestInfo requestInfo;
1044 requestInfo.url = url;
1045 requestInfo.timeoutMs = HTTP_TIME_OUT_MS;
1046 downloadRequest_ = std::make_shared<DownloadRequest>(duration, dataSave_,
1047 realStatusCallback, requestInfo, requestWholeFile);
1048 downloadRequest_->SetDownloadDoneCb(downloadDoneCallback);
1049 downloadRequest_->SetRequestProtocolType(RequestProtocolType::DASH);
1050 if (!requestWholeFile && (endPos > startPos)) {
1051 downloadRequest_->SetRangePos(startPos, endPos);
1052 }
1053 MEDIA_LOG_I("PutRequestIntoDownloader:range=" PUBLIC_LOG_D64 "-" PUBLIC_LOG_D64, startPos, endPos);
1054
1055 isCleaningBuffer_.store(false);
1056 if (downloader_ != nullptr) {
1057 downloader_->Download(downloadRequest_, -1); // -1
1058 downloader_->Start();
1059 }
1060 }
1061
UpdateDownloadFinished(const std::string & url,const std::string & location)1062 void DashSegmentDownloader::UpdateDownloadFinished(const std::string& url, const std::string& location)
1063 {
1064 MEDIA_LOG_I("UpdateDownloadFinished:streamId:" PUBLIC_LOG_D32, streamId_);
1065 if (totalDownloadDuringTime_ > 0) {
1066 double tmpNumerator = static_cast<double>(downloadBits_);
1067 double tmpDenominator = static_cast<double>(totalDownloadDuringTime_);
1068 double downloadRate = tmpNumerator / tmpDenominator;
1069 downloadSpeed_ = downloadRate * SPEED_MULTI_FACT;
1070 } else {
1071 downloadSpeed_ = 0;
1072 }
1073
1074 if (UpdateInitSegmentFinish()) {
1075 if (mediaSegment_ != nullptr) {
1076 PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
1077 mediaSegment_->endRangeValue_, mediaSegment_->url_);
1078 return;
1079 }
1080 }
1081
1082 if (mediaSegment_ != nullptr) {
1083 if (mediaSegment_->contentLength_ == 0 && downloadRequest_ != nullptr) {
1084 mediaSegment_->contentLength_ = downloadRequest_->GetFileContentLength();
1085 }
1086 if (downloadRequest_ != nullptr) {
1087 size_t fragmentSize = mediaSegment_->contentLength_;
1088 double duration = downloadRequest_->GetDuration();
1089 CalculateBitRate(fragmentSize, duration);
1090 downloadBiteRate_ = downloadRequest_->GetBitRate();
1091 }
1092 mediaSegment_->isEos_ = true;
1093 if (mediaSegment_->isLast_) {
1094 MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
1095 isAllSegmentFinished_.store(true);
1096 }
1097 MEDIA_LOG_I("UpdateDownloadFinished: segmentNum:" PUBLIC_LOG_D64 ", contentLength:" PUBLIC_LOG_ZU
1098 ", isCleaningBuffer:" PUBLIC_LOG_D32 " isLast: " PUBLIC_LOG_D32, mediaSegment_->numberSeq_,
1099 mediaSegment_->contentLength_, isCleaningBuffer_.load(), mediaSegment_->isLast_);
1100 }
1101
1102 SaveDataHandleBuffering();
1103 if (downloadDoneCbFunc_ && !isCleaningBuffer_.load()) {
1104 downloadDoneCbFunc_(streamId_);
1105 }
1106 }
1107
UpdateInitSegmentFinish()1108 bool DashSegmentDownloader::UpdateInitSegmentFinish()
1109 {
1110 std::lock_guard<std::mutex> lock(initSegmentMutex_);
1111 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
1112 if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
1113 MEDIA_LOG_I("UpdateInitSegmentFinish:streamId:" PUBLIC_LOG_D32 ", writeState:"
1114 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
1115 initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
1116 initSegment->isDownloadFinish_ = true;
1117 return true;
1118 }
1119
1120 return false;
1121 }
1122
GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment> & currentSegment)1123 uint32_t DashSegmentDownloader::GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment>& currentSegment)
1124 {
1125 if (buffer_->GetHead() > currentSegment->bufferPosHead_) {
1126 return (((currentSegment->bufferPosTail_ - buffer_->GetHead()) * currentSegment->duration_) /
1127 (currentSegment->bufferPosTail_ - currentSegment->bufferPosHead_));
1128 } else {
1129 return currentSegment->duration_;
1130 }
1131 }
1132
GetDashInitSegment(int32_t streamId)1133 std::shared_ptr<DashInitSegment> DashSegmentDownloader::GetDashInitSegment(int32_t streamId)
1134 {
1135 std::shared_ptr<DashInitSegment> segment = nullptr;
1136 auto it = std::find_if(initSegments_.begin(), initSegments_.end(),
1137 [&streamId](const std::shared_ptr<DashInitSegment> &initSegment) -> bool {
1138 return initSegment != nullptr && initSegment->streamId_ == streamId;
1139 });
1140 if (it != initSegments_.end()) {
1141 segment = *it;
1142 }
1143 return segment;
1144 }
1145
SetInterruptState(bool isInterruptNeeded)1146 void DashSegmentDownloader::SetInterruptState(bool isInterruptNeeded)
1147 {
1148 FALSE_RETURN(downloader_ != nullptr && buffer_ != nullptr);
1149 downloader_->SetInterruptState(isInterruptNeeded);
1150 if (isInterruptNeeded) {
1151 buffer_->SetActive(false);
1152 }
1153 }
1154
SetAppUid(int32_t appUid)1155 void DashSegmentDownloader::SetAppUid(int32_t appUid)
1156 {
1157 if (downloader_) {
1158 downloader_->SetAppUid(appUid);
1159 }
1160 }
1161
GetBufferringStatus() const1162 bool DashSegmentDownloader::GetBufferringStatus() const
1163 {
1164 return isBuffering_.load();
1165 }
1166
IsAllSegmentFinished() const1167 bool DashSegmentDownloader::IsAllSegmentFinished() const
1168 {
1169 return isAllSegmentFinished_.load();
1170 }
1171
SetDurationForPlaying(double duration)1172 void DashSegmentDownloader::SetDurationForPlaying(double duration)
1173 {
1174 if (duration > 0 && streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1175 bufferDurationForPlaying_ = duration;
1176 MEDIA_LOG_I("Dash buffer duration for playing : " PUBLIC_LOG ".3f", bufferDurationForPlaying_);
1177 }
1178 }
1179
IsNeedBufferForPlaying()1180 bool DashSegmentDownloader::IsNeedBufferForPlaying()
1181 {
1182 if (bufferDurationForPlaying_ <= 0 || !isDemuxerInitSuccess_.load() || !isBuffering_.load()) {
1183 return false;
1184 }
1185 if (GetBufferingTimeOut() && callback_) {
1186 callback_->OnEvent({PluginEventType::CLIENT_ERROR, {NetworkClientErrorCode::ERROR_TIME_OUT},
1187 "buffer for playing"});
1188 isBuffering_.store(false);
1189 isDemuxerInitSuccess_.store(false);
1190 bufferingTime_ = 0;
1191 return false;
1192 }
1193 if (GetBufferSize() >= waterlineForPlaying_ || isAllSegmentFinished_.load()) {
1194 MEDIA_LOG_I("Dash buffer duration for playing is enough, buffersize: " PUBLIC_LOG_U32 " waterLineAbove: "
1195 PUBLIC_LOG_U64, GetBufferSize(), waterlineForPlaying_);
1196 isBuffering_.store(false);
1197 isDemuxerInitSuccess_.store(false);
1198 bufferingTime_ = 0;
1199 return false;
1200 }
1201 return true;
1202 }
1203
NotifyInitSuccess()1204 void DashSegmentDownloader::NotifyInitSuccess()
1205 {
1206 if (streamType_ != MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1207 return;
1208 }
1209 MEDIA_LOG_I("Dash NotifyInitSuccess in");
1210 isDemuxerInitSuccess_.store(true);
1211 if (bufferDurationForPlaying_ <= 0 || realTimeBitBate_ <= 0) {
1212 return;
1213 }
1214 waterlineForPlaying_ = static_cast<uint64_t>(static_cast<double>(realTimeBitBate_) /
1215 static_cast<double>(BYTES_TO_BIT) * bufferDurationForPlaying_);
1216 isBuffering_.store(true);
1217 bufferingTime_ = static_cast<size_t>(steadyClock_.ElapsedMilliseconds());
1218 }
1219
GetBufferingTimeOut()1220 bool DashSegmentDownloader::GetBufferingTimeOut()
1221 {
1222 if (bufferingTime_ == 0) {
1223 return false;
1224 } else {
1225 size_t now = static_cast<size_t>(steadyClock_.ElapsedMilliseconds());
1226 return now >= bufferingTime_ ? now - bufferingTime_ >= MAX_BUFFERING_TIME_OUT : false;
1227 }
1228 }
1229
CheckLoopTimeout(int64_t startLoopTime)1230 bool DashSegmentDownloader::CheckLoopTimeout(int64_t startLoopTime)
1231 {
1232 int64_t now = loopInterruptClock_.ElapsedSeconds();
1233 int64_t loopDuration = now > startLoopTime ? now - startLoopTime : 0;
1234 bool isLoopTimeOut = loopDuration > LOOP_TIMEOUT ? true : false;
1235 if (isLoopTimeOut) {
1236 MEDIA_LOG_E("loop timeout");
1237 }
1238 return isLoopTimeOut;
1239 }
1240
StopBufferring(bool isAppBackground)1241 Status DashSegmentDownloader::StopBufferring(bool isAppBackground)
1242 {
1243 MEDIA_LOG_I("DashSegmentDownloader:StopBufferring enter");
1244 FALSE_RETURN_V(buffer_ != nullptr && downloader_ != nullptr, Status::ERROR_NULL_POINTER);
1245 downloader_->SetAppState(isAppBackground);
1246 if (isAppBackground) {
1247 buffer_->SetActive(false, false);
1248 } else {
1249 buffer_->SetActive(true, false);
1250 }
1251 downloader_->StopBufferring();
1252 return Status::OK;
1253 }
1254 }
1255 }
1256 }
1257 }