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