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 std::lock_guard<std::mutex> lock(initSegmentMutex_);
454 for (auto it = initSegments_.begin(); it != initSegments_.end(); ++it) {
455 if ((*it)->streamId_ == currentStreamId) {
456 MEDIA_LOG_I("UpdateInitSegmentState: init streamId:" PUBLIC_LOG_D32 ", contentLen:"
457 PUBLIC_LOG_ZU ", readIndex:" PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
458 PUBLIC_LOG_D32, currentStreamId, (*it)->content_.length(), (*it)->readIndex_,
459 (*it)->isDownloadFinish_, (*it)->readState_);
460 }
461 (*it)->readIndex_ = 0;
462 (*it)->readState_ = INIT_SEGMENT_STATE_UNUSE;
463 }
464 }
465
ReadInitSegment(uint8_t * buff,uint32_t wantReadLength,uint32_t & realReadLength,int32_t currentStreamId)466 bool DashSegmentDownloader::ReadInitSegment(uint8_t *buff, uint32_t wantReadLength, uint32_t &realReadLength,
467 int32_t currentStreamId)
468 {
469 std::lock_guard<std::mutex> lock(initSegmentMutex_);
470 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(currentStreamId);
471 if (initSegment != nullptr && initSegment->readState_ != INIT_SEGMENT_STATE_USED) {
472 unsigned int contentLen = initSegment->content_.length();
473 MEDIA_LOG_I("Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex:"
474 PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
475 PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
476 initSegment->isDownloadFinish_, initSegment->readState_);
477 if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
478 // init segment read finish
479 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
480 initSegment->readIndex_ = 0;
481 return true;
482 }
483
484 unsigned int unReadSize = contentLen - initSegment->readIndex_;
485 if (unReadSize > 0) {
486 realReadLength = unReadSize > wantReadLength ? wantReadLength : unReadSize;
487 std::string readStr = initSegment->content_.substr(initSegment->readIndex_);
488 memcpy_s(buff, wantReadLength, readStr.c_str(), realReadLength);
489 initSegment->readIndex_ += realReadLength;
490 if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
491 // init segment read finish
492 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
493 initSegment->readIndex_ = 0;
494 }
495 }
496
497 MEDIA_LOG_I("after Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex_:"
498 PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
499 initSegment->isDownloadFinish_);
500 return true;
501 }
502 return false;
503 }
504
ClearReadSegmentList()505 void DashSegmentDownloader::ClearReadSegmentList()
506 {
507 std::lock_guard<std::mutex> lock(segmentMutex_);
508 for (auto it = segmentList_.begin(); it != segmentList_.end(); ++it) {
509 if (buffer_->GetHead() != 0 && (*it)->isEos_ && buffer_->GetHead() >= (*it)->bufferPosTail_) {
510 MEDIA_LOG_D("Read:streamId:" PUBLIC_LOG_D32 ", erase numberSeq:"
511 PUBLIC_LOG_D64, (*it)->streamId_, (*it)->numberSeq_);
512 it = segmentList_.erase(it);
513 } else {
514 break;
515 }
516 }
517 }
518
SetStatusCallback(StatusCallbackFunc statusCallbackFunc)519 void DashSegmentDownloader::SetStatusCallback(StatusCallbackFunc statusCallbackFunc)
520 {
521 statusCallback_ = statusCallbackFunc;
522 }
523
SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)524 void DashSegmentDownloader::SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)
525 {
526 downloadDoneCbFunc_ = doneCbFunc;
527 }
528
GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const529 size_t DashSegmentDownloader::GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const
530 {
531 size_t ringBufferFixSize = DEFAULT_RING_BUFFER_SIZE;
532 auto ringBufferSizeItem = BUFFER_SIZE_MAP.find(streamType);
533 if (ringBufferSizeItem != BUFFER_SIZE_MAP.end()) {
534 ringBufferFixSize = ringBufferSizeItem->second;
535 }
536
537 if (streamType == MediaAVCodec::MediaType::MEDIA_TYPE_VID && userDefinedBufferDuration_) {
538 size_t ringBufferSize = expectDuration_ * currentBitrate_;
539 if (ringBufferSize < DEFAULT_RING_BUFFER_SIZE) {
540 MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already lower than the min buffer size: "
541 PUBLIC_LOG_U32 ", setting buffer size: "
542 PUBLIC_LOG_U32, ringBufferSize, DEFAULT_RING_BUFFER_SIZE, DEFAULT_RING_BUFFER_SIZE);
543 ringBufferSize = DEFAULT_RING_BUFFER_SIZE;
544 } else if (ringBufferSize > ringBufferFixSize) {
545 MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already exceed the max buffer size: "
546 PUBLIC_LOG_ZU ", setting buffer size: "
547 PUBLIC_LOG_ZU, ringBufferSize, ringBufferFixSize, ringBufferFixSize);
548 ringBufferSize = ringBufferFixSize;
549 }
550 return ringBufferSize;
551 } else {
552 return ringBufferFixSize;
553 }
554 }
555
SetInitSegment(std::shared_ptr<DashInitSegment> initSegment,bool needUpdateState)556 void DashSegmentDownloader::SetInitSegment(std::shared_ptr<DashInitSegment> initSegment, bool needUpdateState)
557 {
558 if (initSegment == nullptr) {
559 return;
560 }
561
562 std::lock_guard<std::mutex> lock(initSegmentMutex_);
563 int streamId = initSegment->streamId_;
564 std::shared_ptr<DashInitSegment> dashInitSegment = GetDashInitSegment(streamId);
565 if (dashInitSegment == nullptr) {
566 initSegments_.push_back(initSegment);
567 dashInitSegment = initSegment;
568 needUpdateState = true;
569 }
570
571 if (!dashInitSegment->isDownloadFinish_) {
572 dashInitSegment->writeState_ = INIT_SEGMENT_STATE_UNUSE;
573 }
574
575 // seek or first time to set stream init segment should update to UNUSE
576 // read will update state to UNUSE when stream id is changed
577 if (needUpdateState) {
578 dashInitSegment->readState_ = INIT_SEGMENT_STATE_UNUSE;
579 }
580 MEDIA_LOG_I("SetInitSegment:streamId:" PUBLIC_LOG_D32 ", isDownloadFinish_="
581 PUBLIC_LOG_D32 ", readIndex=" PUBLIC_LOG_U32 ", readState_=" PUBLIC_LOG_D32 ", update="
582 PUBLIC_LOG_D32 ", writeState_=" PUBLIC_LOG_D32, streamId, dashInitSegment->isDownloadFinish_,
583 dashInitSegment->readIndex_, dashInitSegment->readState_, needUpdateState, dashInitSegment->writeState_);
584 }
585
UpdateStreamId(int streamId)586 void DashSegmentDownloader::UpdateStreamId(int streamId)
587 {
588 streamId_ = streamId;
589 }
590
SetCurrentBitRate(int32_t bitRate)591 void DashSegmentDownloader::SetCurrentBitRate(int32_t bitRate)
592 {
593 if (bitRate <= 0) {
594 realTimeBitBate_ = -1;
595 } else {
596 realTimeBitBate_ = static_cast<int64_t>(bitRate);
597 }
598 }
599
SetDemuxerState()600 void DashSegmentDownloader::SetDemuxerState()
601 {
602 isFirstFrameArrived_ = true;
603 }
604
SetAllSegmentFinished()605 void DashSegmentDownloader::SetAllSegmentFinished()
606 {
607 MEDIA_LOG_I("SetAllSegmentFinished streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
608 isAllSegmentFinished_.store(true);
609 }
610
GetStreamId() const611 int DashSegmentDownloader::GetStreamId() const
612 {
613 return streamId_;
614 }
615
GetStreamType() const616 MediaAVCodec::MediaType DashSegmentDownloader::GetStreamType() const
617 {
618 return streamType_;
619 }
620
GetContentLength()621 size_t DashSegmentDownloader::GetContentLength()
622 {
623 if (downloadRequest_ == nullptr || downloadRequest_->IsClosed()) {
624 return 0; // 0
625 }
626 return downloadRequest_->GetFileContentLength();
627 }
628
GetStartedStatus() const629 bool DashSegmentDownloader::GetStartedStatus() const
630 {
631 return startedPlayStatus_;
632 }
633
IsSegmentFinish() const634 bool DashSegmentDownloader::IsSegmentFinish() const
635 {
636 if (mediaSegment_ != nullptr && mediaSegment_->isEos_) {
637 return true;
638 }
639
640 return false;
641 }
642
CleanAllSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)643 bool DashSegmentDownloader::CleanAllSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
644 {
645 if (isCleanAll) {
646 MEDIA_LOG_I("CleanAllSegmentBuffer clean all");
647 isCleaningBuffer_.store(true);
648 Close(true, true);
649 std::lock_guard<std::mutex> lock(segmentMutex_);
650 isAllSegmentFinished_.store(false);
651 for (const auto &it: segmentList_) {
652 if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
653 continue;
654 }
655
656 remainLastNumberSeq = it->numberSeq_;
657 break;
658 }
659
660 downloader_ = std::make_shared<Downloader>("dashSegment");
661 buffer_->Clear();
662 segmentList_.clear();
663 buffer_->SetActive(true);
664 return true;
665 }
666
667 return false;
668 }
669
CleanSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)670 bool DashSegmentDownloader::CleanSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
671 {
672 if (CleanAllSegmentBuffer(isCleanAll, remainLastNumberSeq)) {
673 return true;
674 }
675
676 size_t clearTail = 0;
677 {
678 std::lock_guard<std::mutex> lock(segmentMutex_);
679 remainLastNumberSeq = -1;
680 uint32_t remainDuration = 0;
681 for (const auto &it: segmentList_) {
682 if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
683 continue;
684 }
685
686 remainLastNumberSeq = it->numberSeq_;
687
688 if (!it->isEos_) {
689 break;
690 }
691
692 remainDuration += GetSegmentRemainDuration(it);
693 if (remainDuration >= MIN_RETENTION_DURATION_MS) {
694 clearTail = it->bufferPosTail_;
695 break;
696 }
697 }
698
699 MEDIA_LOG_I("CleanSegmentBuffer:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
700 PUBLIC_LOG_D64, streamId_, remainLastNumberSeq);
701 }
702
703 if (clearTail > 0) {
704 isCleaningBuffer_.store(true);
705 Close(true, false);
706 std::lock_guard<std::mutex> lock(segmentMutex_);
707 isAllSegmentFinished_.store(false);
708 segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
709 return (bufferSegment->numberSeq_ > remainLastNumberSeq);
710 });
711
712 downloader_ = std::make_shared<Downloader>("dashSegment");
713 MEDIA_LOG_I("CleanSegmentBuffer bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
714 PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(), clearTail);
715 buffer_->SetTail(clearTail);
716 buffer_->SetActive(true);
717 return true;
718 }
719 return false;
720 }
721
CleanByTimeInternal(int64_t & remainLastNumberSeq,size_t & clearTail,bool & isEnd)722 void DashSegmentDownloader::CleanByTimeInternal(int64_t& remainLastNumberSeq, size_t& clearTail, bool& isEnd)
723 {
724 // residue segment duration
725 uint32_t remainDuration = 0;
726 uint32_t segmentKeepDuration = 1000; // ms
727 uint32_t segmentKeepDelta = 100; // ms
728 for (const auto &it: segmentList_) {
729 if (it == nullptr ||
730 buffer_->GetHead() > it->bufferPosTail_ ||
731 it->bufferPosHead_ >= it->bufferPosTail_) {
732 continue;
733 }
734
735 remainLastNumberSeq = it->numberSeq_;
736 isEnd = it->isEos_;
737 if (it->contentLength_ == 0 ||
738 it->duration_ == 0) {
739 MEDIA_LOG_I("CleanByTimeInternal: contentLength is:" PUBLIC_LOG_ZU ", duration is:"
740 PUBLIC_LOG_U32, it->contentLength_, it->duration_);
741 // can not caculate segment content length, just keep one segment
742 clearTail = it->bufferPosTail_;
743 break;
744 }
745
746 remainDuration = (it->bufferPosTail_ - buffer_->GetHead()) * it->duration_ / it->contentLength_;
747 if (remainDuration < segmentKeepDuration + segmentKeepDelta &&
748 remainDuration + segmentKeepDelta >= segmentKeepDuration) {
749 // find clear buffer position with segment tail position
750 clearTail = it->bufferPosTail_;
751 } else if (remainDuration < segmentKeepDuration) {
752 // get next segment buffer
753 clearTail = it->bufferPosTail_;
754 segmentKeepDuration -= remainDuration;
755 continue;
756 } else {
757 // find clear buffer position
758 uint32_t segmentSize = (segmentKeepDuration * it->contentLength_) / it->duration_;
759 if (clearTail > 0) {
760 // find clear buffer position in multi segments
761 clearTail += segmentSize;
762 } else {
763 // find clear buffer position in one segment
764 clearTail = buffer_->GetHead() + segmentSize;
765 }
766 it->bufferPosTail_ = clearTail;
767 it->isEos_ = true;
768 isEnd = false;
769 }
770
771 break;
772 }
773 }
774
CleanBufferByTime(int64_t & remainLastNumberSeq,bool & isEnd)775 bool DashSegmentDownloader::CleanBufferByTime(int64_t& remainLastNumberSeq, bool& isEnd)
776 {
777 Close(true, false);
778 std::lock_guard<std::mutex> lock(segmentMutex_);
779 remainLastNumberSeq = -1;
780 size_t clearTail = 0;
781 CleanByTimeInternal(remainLastNumberSeq, clearTail, isEnd);
782
783 if (remainLastNumberSeq == -1 && mediaSegment_ != nullptr) {
784 isEnd = false;
785 }
786
787 MEDIA_LOG_I("CleanBufferByTime:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
788 PUBLIC_LOG_D64 ", isEnd:" PUBLIC_LOG_D32 ", size:" PUBLIC_LOG_ZU, streamId_,
789 remainLastNumberSeq, isEnd, segmentList_.size());
790
791 if (clearTail > 0) {
792 isCleaningBuffer_.store(true);
793 segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
794 return (bufferSegment->numberSeq_ > remainLastNumberSeq);
795 });
796
797 downloader_ = std::make_shared<Downloader>("dashSegment");
798 MEDIA_LOG_I("CleanBufferByTime bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
799 PUBLIC_LOG_ZU " ,seq:" PUBLIC_LOG_D64 ",size:" PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(),
800 clearTail, remainLastNumberSeq, segmentList_.size());
801 buffer_->SetTail(clearTail);
802 buffer_->SetActive(true);
803 return true;
804 }
805 return false;
806 }
807
SeekToTime(const std::shared_ptr<DashSegment> & segment,int32_t & streamId)808 bool DashSegmentDownloader::SeekToTime(const std::shared_ptr<DashSegment> &segment, int32_t& streamId)
809 {
810 std::lock_guard<std::mutex> lock(segmentMutex_);
811 std::shared_ptr<DashBufferSegment> desSegment;
812 auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
813 [&segment](const std::shared_ptr<DashBufferSegment> &item) -> bool {
814 return (item->numberSeq_ - item->startNumberSeq_) == (segment->numberSeq_ - segment->startNumberSeq_);
815 });
816 if (it != segmentList_.end()) {
817 desSegment = *it;
818 }
819
820 if (desSegment != nullptr && desSegment->bufferPosTail_ > 0) {
821 if (buffer_->SetHead(desSegment->bufferPosHead_)) {
822 // set init segment when seek on buffered, before read first segment demuxer plugin need reboot
823 UpdateInitSegmentState(desSegment->streamId_);
824 streamId = desSegment->streamId_;
825 return true;
826 }
827 }
828 return false;
829 }
830
SaveData(uint8_t * data,uint32_t len)831 bool DashSegmentDownloader::SaveData(uint8_t* data, uint32_t len)
832 {
833 MEDIA_LOG_D("SaveData:streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
834 startedPlayStatus_ = true;
835 if (streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
836 OnWriteRingBuffer(len);
837 }
838 {
839 std::lock_guard<std::mutex> lock(initSegmentMutex_);
840 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
841 if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
842 MEDIA_LOG_I("SaveData:streamId:" PUBLIC_LOG_D32 ", writeState:"
843 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
844 initSegment->content_.append(reinterpret_cast<const char*>(data), len);
845 return true;
846 }
847 }
848
849 size_t bufferTail = buffer_->GetTail();
850 bool writeRet = buffer_->WriteBuffer(data, len);
851 HandleCachedDuration();
852 SaveDataHandleBuffering();
853 if (!writeRet) {
854 MEDIA_LOG_E("SaveData:error streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
855 return writeRet;
856 }
857
858 std::lock_guard<std::mutex> lock(segmentMutex_);
859 for (const auto &mediaSegment: segmentList_) {
860 if (mediaSegment == nullptr || mediaSegment->isEos_) {
861 continue;
862 }
863
864 if (mediaSegment->bufferPosTail_ == 0) {
865 mediaSegment->bufferPosHead_ = bufferTail;
866 }
867 mediaSegment->bufferPosTail_ = buffer_->GetTail();
868 UpdateBufferSegment(mediaSegment, len);
869 break;
870 }
871 return writeRet;
872 }
873
UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> & mediaSegment,uint32_t len)874 void DashSegmentDownloader::UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> &mediaSegment, uint32_t len)
875 {
876 if (mediaSegment->contentLength_ == 0 && downloadRequest_ != nullptr) {
877 mediaSegment->contentLength_ = downloadRequest_->GetFileContentLength();
878 }
879
880 // last packet len is 0 of chunk
881 if (len == 0 || (mediaSegment->contentLength_ > 0 &&
882 mediaSegment->bufferPosTail_ >= (mediaSegment->bufferPosHead_ + mediaSegment->contentLength_))) {
883 mediaSegment->isEos_ = true;
884 if (mediaSegment->isLast_) {
885 MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
886 isAllSegmentFinished_.store(true);
887 }
888 if (mediaSegment->contentLength_ == 0) {
889 mediaSegment->contentLength_ = mediaSegment->bufferPosTail_ - mediaSegment->bufferPosHead_;
890 }
891 MEDIA_LOG_I("SaveData eos:streamId:" PUBLIC_LOG_D32 ", segmentNum:" PUBLIC_LOG_D64 ", contentLength:"
892 PUBLIC_LOG_ZU ", bufferPosHead:" PUBLIC_LOG_ZU " ,bufferPosEnd:" PUBLIC_LOG_ZU,
893 mediaSegment->streamId_, mediaSegment->numberSeq_, mediaSegment->contentLength_,
894 mediaSegment->bufferPosHead_, mediaSegment->bufferPosTail_);
895 }
896 }
897
OnWriteRingBuffer(uint32_t len)898 void DashSegmentDownloader::OnWriteRingBuffer(uint32_t len)
899 {
900 uint32_t writeBits = len * BYTE_TO_BIT;
901 totalBits_ += writeBits;
902 uint64_t now = static_cast<uint64_t>(steadyClock_.ElapsedMilliseconds());
903 if (now > lastCheckTime_ && now - lastCheckTime_ > RECORD_TIME_INTERVAL) {
904 uint64_t curDownloadBits = totalBits_ - lastBits_;
905 if (curDownloadBits >= RECORD_DOWNLOAD_MIN_BIT) {
906 downloadDuringTime_ = now - lastCheckTime_;
907 downloadBits_ += curDownloadBits;
908 totalDownloadDuringTime_ += downloadDuringTime_;
909 double downloadRate = 0;
910 double tmpNumerator = static_cast<double>(curDownloadBits);
911 double tmpDenominator = static_cast<double>(downloadDuringTime_) / SECOND_TO_MILLIONSECOND;
912 if (tmpDenominator > ZERO_THRESHOLD) {
913 downloadRate = tmpNumerator / tmpDenominator;
914 }
915 size_t remainingBuffer = 0;
916 if (buffer_ != nullptr) {
917 remainingBuffer = buffer_->GetSize();
918 }
919 MEDIA_LOG_D("Current download speed : " PUBLIC_LOG_D32 " Kbit/s,Current buffer size : " PUBLIC_LOG_U64
920 " KByte", static_cast<int32_t>(downloadRate / 1024), static_cast<uint64_t>(remainingBuffer / 1024));
921 // Remaining playable time: s
922 uint64_t bufferDuration = 0;
923 if (realTimeBitBate_ > 0) {
924 bufferDuration =
925 remainingBuffer * static_cast<uint64_t>(BYTES_TO_BIT) / static_cast<uint64_t>(realTimeBitBate_);
926 } else {
927 bufferDuration = static_cast<uint64_t>(remainingBuffer * BYTES_TO_BIT) / currentBitrate_;
928 }
929 if (recordData_ != nullptr) {
930 recordData_->downloadRate = downloadRate;
931 recordData_->bufferDuring = bufferDuration;
932 }
933 }
934 lastBits_ = totalBits_;
935 lastCheckTime_ = now;
936 }
937 }
938
GetDownloadSpeed() const939 uint64_t DashSegmentDownloader::GetDownloadSpeed() const
940 {
941 return static_cast<uint64_t>(downloadSpeed_);
942 }
943
GetIp(std::string & ip)944 void DashSegmentDownloader::GetIp(std::string& ip)
945 {
946 if (downloader_) {
947 downloader_->GetIp(ip);
948 }
949 }
950
GetDownloadFinishState()951 bool DashSegmentDownloader::GetDownloadFinishState()
952 {
953 std::shared_ptr<DashInitSegment> finishState = GetDashInitSegment(streamId_);
954 if (finishState) {
955 return finishState->isDownloadFinish_;
956 } else {
957 return true;
958 }
959 }
960
GetDownloadRecordData()961 std::pair<int64_t, int64_t> DashSegmentDownloader::GetDownloadRecordData()
962 {
963 std::pair<int64_t, int64_t> recordData;
964 if (recordData_ != nullptr) {
965 recordData.first = static_cast<int64_t>(recordData_->downloadRate);
966 recordData.second = static_cast<int64_t>(recordData_->bufferDuring);
967 } else {
968 recordData.first = 0;
969 recordData.second = 0;
970 }
971 return recordData;
972 }
973
GetBufferSize() const974 uint32_t DashSegmentDownloader::GetBufferSize() const
975 {
976 if (buffer_ != nullptr) {
977 return buffer_->GetSize();
978 }
979 return 0;
980 }
981
GetRingBufferCapacity() const982 uint32_t DashSegmentDownloader::GetRingBufferCapacity() const
983 {
984 return ringBufferCapcity_;
985 }
986
PutRequestIntoDownloader(unsigned int duration,int64_t startPos,int64_t endPos,const std::string & url)987 void DashSegmentDownloader::PutRequestIntoDownloader(unsigned int duration, int64_t startPos, int64_t endPos,
988 const std::string &url)
989 {
990 auto realStatusCallback = [this](DownloadStatus &&status, std::shared_ptr<Downloader> &downloader,
991 std::shared_ptr<DownloadRequest> &request) {
992 statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
993 };
994 auto downloadDoneCallback = [this](const std::string &url, const std::string &location) {
995 UpdateDownloadFinished(url, location);
996 };
997
998 bool requestWholeFile = true;
999 if (startPos >= 0 && endPos > 0) {
1000 requestWholeFile = false;
1001 }
1002 RequestInfo requestInfo;
1003 requestInfo.url = url;
1004 requestInfo.timeoutMs = HTTP_TIME_OUT_MS;
1005 downloadRequest_ = std::make_shared<DownloadRequest>(duration, dataSave_,
1006 realStatusCallback, requestInfo, requestWholeFile);
1007 downloadRequest_->SetDownloadDoneCb(downloadDoneCallback);
1008 if (!requestWholeFile && (endPos > startPos)) {
1009 downloadRequest_->SetRangePos(startPos, endPos);
1010 }
1011 MEDIA_LOG_I("PutRequestIntoDownloader:range=" PUBLIC_LOG_D64 "-" PUBLIC_LOG_D64, startPos, endPos);
1012
1013 isCleaningBuffer_.store(false);
1014 if (downloader_ != nullptr) {
1015 downloader_->Download(downloadRequest_, -1); // -1
1016 downloader_->Start();
1017 }
1018 }
1019
UpdateDownloadFinished(const std::string & url,const std::string & location)1020 void DashSegmentDownloader::UpdateDownloadFinished(const std::string& url, const std::string& location)
1021 {
1022 MEDIA_LOG_I("UpdateDownloadFinished:streamId:" PUBLIC_LOG_D32, streamId_);
1023 if (totalDownloadDuringTime_ > 0) {
1024 double tmpNumerator = static_cast<double>(downloadBits_);
1025 double tmpDenominator = static_cast<double>(totalDownloadDuringTime_);
1026 double downloadRate = tmpNumerator / tmpDenominator;
1027 downloadSpeed_ = downloadRate * SPEED_MULTI_FACT;
1028 } else {
1029 downloadSpeed_ = 0;
1030 }
1031
1032 if (UpdateInitSegmentFinish()) {
1033 if (mediaSegment_ != nullptr) {
1034 PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
1035 mediaSegment_->endRangeValue_, mediaSegment_->url_);
1036 return;
1037 }
1038 }
1039
1040 if (mediaSegment_ != nullptr) {
1041 if (mediaSegment_->contentLength_ == 0 && downloadRequest_ != nullptr) {
1042 mediaSegment_->contentLength_ = downloadRequest_->GetFileContentLength();
1043 }
1044 if (downloadRequest_ != nullptr) {
1045 size_t fragmentSize = mediaSegment_->contentLength_;
1046 double duration = downloadRequest_->GetDuration();
1047 CalculateBitRate(fragmentSize, duration);
1048 downloadBiteRate_ = downloadRequest_->GetBitRate();
1049 }
1050 mediaSegment_->isEos_ = true;
1051 if (mediaSegment_->isLast_) {
1052 MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
1053 isAllSegmentFinished_.store(true);
1054 }
1055 MEDIA_LOG_I("UpdateDownloadFinished: segmentNum:" PUBLIC_LOG_D64 ", contentLength:" PUBLIC_LOG_ZU
1056 ", isCleaningBuffer:" PUBLIC_LOG_D32 " isLast: " PUBLIC_LOG_D32, mediaSegment_->numberSeq_,
1057 mediaSegment_->contentLength_, isCleaningBuffer_.load(), mediaSegment_->isLast_);
1058 }
1059
1060 SaveDataHandleBuffering();
1061 if (downloadDoneCbFunc_ && !isCleaningBuffer_.load()) {
1062 downloadDoneCbFunc_(streamId_);
1063 }
1064 }
1065
UpdateInitSegmentFinish()1066 bool DashSegmentDownloader::UpdateInitSegmentFinish()
1067 {
1068 std::lock_guard<std::mutex> lock(initSegmentMutex_);
1069 std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
1070 if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
1071 MEDIA_LOG_I("UpdateInitSegmentFinish:streamId:" PUBLIC_LOG_D32 ", writeState:"
1072 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
1073 initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
1074 initSegment->isDownloadFinish_ = true;
1075 return true;
1076 }
1077
1078 return false;
1079 }
1080
GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment> & currentSegment)1081 uint32_t DashSegmentDownloader::GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment>& currentSegment)
1082 {
1083 if (buffer_->GetHead() > currentSegment->bufferPosHead_) {
1084 return (((currentSegment->bufferPosTail_ - buffer_->GetHead()) * currentSegment->duration_) /
1085 (currentSegment->bufferPosTail_ - currentSegment->bufferPosHead_));
1086 } else {
1087 return currentSegment->duration_;
1088 }
1089 }
1090
GetDashInitSegment(int32_t streamId)1091 std::shared_ptr<DashInitSegment> DashSegmentDownloader::GetDashInitSegment(int32_t streamId)
1092 {
1093 std::shared_ptr<DashInitSegment> segment = nullptr;
1094 auto it = std::find_if(initSegments_.begin(), initSegments_.end(),
1095 [&streamId](const std::shared_ptr<DashInitSegment> &initSegment) -> bool {
1096 return initSegment != nullptr && initSegment->streamId_ == streamId;
1097 });
1098 if (it != initSegments_.end()) {
1099 segment = *it;
1100 }
1101 return segment;
1102 }
1103
SetInterruptState(bool isInterruptNeeded)1104 void DashSegmentDownloader::SetInterruptState(bool isInterruptNeeded)
1105 {
1106 if (downloader_ != nullptr) {
1107 downloader_->SetInterruptState(isInterruptNeeded);
1108 }
1109 }
1110
SetAppUid(int32_t appUid)1111 void DashSegmentDownloader::SetAppUid(int32_t appUid)
1112 {
1113 if (downloader_) {
1114 downloader_->SetAppUid(appUid);
1115 }
1116 }
1117
GetBufferringStatus() const1118 bool DashSegmentDownloader::GetBufferringStatus() const
1119 {
1120 return isBuffering_.load();
1121 }
1122
IsAllSegmentFinished() const1123 bool DashSegmentDownloader::IsAllSegmentFinished() const
1124 {
1125 return isAllSegmentFinished_.load();
1126 }
1127 }
1128 }
1129 }
1130 }