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