1 /*
2 * Copyright (c) 2022-2022 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 "DashMpdDownloader"
16 #include <mutex>
17 #include <unistd.h>
18 #include <cstdlib>
19 #include <limits>
20 #include <sstream>
21 #include <iomanip>
22 #include <algorithm>
23 #include "plugin/plugin_time.h"
24 #include "network/network_typs.h"
25 #include "dash_mpd_downloader.h"
26 #include "dash_mpd_util.h"
27 #include "sidx_box_parser.h"
28 #include "utils/time_utils.h"
29 #include "base64_utils.h"
30
31 namespace OHOS {
32 namespace Media {
33 namespace Plugins {
34 namespace HttpPlugin {
35 constexpr uint32_t DRM_UUID_OFFSET = 12;
36 constexpr size_t RETRY_TIMES = 15000;
37 constexpr unsigned int SLEEP_TIME = 1;
38 constexpr int32_t MPD_HTTP_TIME_OUT_MS = 5 * 1000;
39 constexpr unsigned int SEGMENT_DURATION_DELTA = 100; // ms
40
DashMpdDownloader(std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)41 DashMpdDownloader::DashMpdDownloader(std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)
42 {
43 if (sourceLoader != nullptr) {
44 MEDIA_LOG_I("DashMpdDownloader app download.");
45 downloader_ = std::make_shared<Downloader>("dashMpd", sourceLoader);
46 } else {
47 downloader_ = std::make_shared<Downloader>("dashMpd");
48 }
49
50 dataSave_ = [this] (uint8_t*&& data, uint32_t&& len, bool&& notBlock) {
51 return SaveData(std::forward<decltype(data)>(data), std::forward<decltype(len)>(len),
52 std::forward<decltype(notBlock)>(notBlock));
53 };
54
55 mpdParser_ = std::make_shared<DashMpdParser>();
56 mpdManager_ = std::make_shared<DashMpdManager>();
57 periodManager_ = std::make_shared<DashPeriodManager>();
58 adptSetManager_ = std::make_shared<DashAdptSetManager>();
59 representationManager_ = std::make_shared<DashRepresentationManager>();
60 }
61
~DashMpdDownloader()62 DashMpdDownloader::~DashMpdDownloader() noexcept
63 {
64 if (downloader_ != nullptr) {
65 downloader_->Stop(false);
66 }
67 streamDescriptions_.clear();
68 }
69
GetContentType()70 std::string DashMpdDownloader::GetContentType()
71 {
72 FALSE_RETURN_V(downloader_ != nullptr, "");
73 return downloader_->GetContentType();
74 }
75
ParseStartNumber(const std::string & numberStr)76 static int64_t ParseStartNumber(const std::string &numberStr)
77 {
78 int64_t startNum = 1;
79 if (numberStr.length() > 0) {
80 startNum = atoi(numberStr.c_str());
81 }
82
83 return startNum;
84 }
85
GetStartNumber(const DashRepresentationInfo * repInfo)86 static int64_t GetStartNumber(const DashRepresentationInfo* repInfo)
87 {
88 int64_t startNumberSeq = 1;
89 if (repInfo->representationSegTmplt_ != nullptr) {
90 startNumberSeq = ParseStartNumber(repInfo->representationSegTmplt_->multSegBaseInfo_.startNumber_);
91 } else if (repInfo->representationSegList_ != nullptr) {
92 startNumberSeq = ParseStartNumber(repInfo->representationSegList_->multSegBaseInfo_.startNumber_);
93 }
94 return startNumberSeq;
95 }
96
GetStartNumber(const DashAdptSetInfo * adptSetInfo)97 static int64_t GetStartNumber(const DashAdptSetInfo* adptSetInfo)
98 {
99 int64_t startNumberSeq = 1;
100 if (adptSetInfo->adptSetSegTmplt_ != nullptr) {
101 startNumberSeq = ParseStartNumber(adptSetInfo->adptSetSegTmplt_->multSegBaseInfo_.startNumber_);
102 } else if (adptSetInfo->adptSetSegList_ != nullptr) {
103 startNumberSeq = ParseStartNumber(adptSetInfo->adptSetSegList_->multSegBaseInfo_.startNumber_);
104 }
105 return startNumberSeq;
106 }
107
GetStartNumber(const DashPeriodInfo * periodInfo)108 static int64_t GetStartNumber(const DashPeriodInfo* periodInfo)
109 {
110 int64_t startNumberSeq = 1;
111 if (periodInfo->periodSegTmplt_ != nullptr) {
112 startNumberSeq = ParseStartNumber(periodInfo->periodSegTmplt_->multSegBaseInfo_.startNumber_);
113 } else if (periodInfo->periodSegList_ != nullptr) {
114 startNumberSeq = ParseStartNumber(periodInfo->periodSegList_->multSegBaseInfo_.startNumber_);
115 }
116 return startNumberSeq;
117 }
118
MakeAbsoluteWithBaseUrl(const std::vector<std::shared_ptr<DashSegment>> & segmentsVector,const std::string & baseUrl)119 static void MakeAbsoluteWithBaseUrl(const std::vector<std::shared_ptr<DashSegment>> &segmentsVector,
120 const std::string &baseUrl)
121 {
122 std::string segUrl;
123 unsigned int size = segmentsVector.size();
124
125 for (unsigned int index = 0; index < size; index++) {
126 if (segmentsVector[index] != nullptr) {
127 segUrl = baseUrl;
128 DashAppendBaseUrl(segUrl, segmentsVector[index]->url_);
129 segmentsVector[index]->url_ = segUrl;
130 }
131 }
132 }
133
MakeAbsoluteWithBaseUrl(std::shared_ptr<DashInitSegment> initSegment,const std::string & baseUrl)134 static void MakeAbsoluteWithBaseUrl(std::shared_ptr<DashInitSegment> initSegment, const std::string &baseUrl)
135 {
136 if (initSegment == nullptr) {
137 return;
138 }
139
140 if (DashUrlIsAbsolute(initSegment->url_)) {
141 return;
142 }
143
144 std::string segUrl = baseUrl;
145 DashAppendBaseUrl(segUrl, initSegment->url_);
146 initSegment->url_ = segUrl;
147 }
148
AddOneSegment(unsigned int segRealDur,int64_t segmentSeq,const std::string & tempUrl,std::shared_ptr<DashStreamDescription> streamDesc)149 static DashSegmentInitValue AddOneSegment(unsigned int segRealDur, int64_t segmentSeq, const std::string &tempUrl,
150 std::shared_ptr<DashStreamDescription> streamDesc)
151 {
152 std::shared_ptr<DashSegment> segment = std::make_shared<DashSegment>();
153 segment->streamId_ = streamDesc->streamId_;
154 segment->bandwidth_ = streamDesc->bandwidth_;
155 segment->duration_ = segRealDur;
156 segment->startNumberSeq_ = streamDesc->startNumberSeq_;
157 segment->numberSeq_ = segmentSeq;
158 segment->url_ = tempUrl;
159 segment->byteRange_ = "";
160 streamDesc->mediaSegments_.push_back(segment);
161 return DASH_SEGMENT_INIT_SUCCESS;
162 }
163
AddOneSegment(const DashSegment & srcSegment,std::shared_ptr<DashStreamDescription> streamDesc)164 static DashSegmentInitValue AddOneSegment(const DashSegment &srcSegment,
165 std::shared_ptr<DashStreamDescription> streamDesc)
166 {
167 std::shared_ptr<DashSegment> segment = std::make_shared<DashSegment>(srcSegment);
168 streamDesc->mediaSegments_.push_back(segment);
169 return DASH_SEGMENT_INIT_SUCCESS;
170 }
171
172 /**
173 * @brief Get Representation From AdaptationSet
174 *
175 * @param adptSet chosen AdaptationSet
176 * @param repreIndex Representation index in AdaptationSet
177 *
178 * @return chosen representation
179 */
GetRepresentationFromAdptSet(DashAdptSetInfo * adptSet,unsigned int repreIndex)180 static DashRepresentationInfo* GetRepresentationFromAdptSet(DashAdptSetInfo* adptSet, unsigned int repreIndex)
181 {
182 if (repreIndex >= adptSet->representationList_.size()) {
183 return nullptr;
184 }
185
186 unsigned int index = 0;
187 for (DashList<DashRepresentationInfo *>::iterator it = adptSet->representationList_.begin();
188 it != adptSet->representationList_.end(); ++it, ++index) {
189 if (index == repreIndex) {
190 return *it;
191 }
192 }
193 return nullptr;
194 }
195
Open(const std::string & url)196 void DashMpdDownloader::Open(const std::string &url)
197 {
198 url_ = url;
199 DoOpen(url);
200 }
201
Close(bool isAsync)202 void DashMpdDownloader::Close(bool isAsync)
203 {
204 downloader_->Stop(isAsync);
205
206 if (downloadRequest_ != nullptr && !downloadRequest_->IsClosed()) {
207 downloadRequest_->Close();
208 }
209 }
210
SetStatusCallback(StatusCallbackFunc cb)211 void DashMpdDownloader::SetStatusCallback(StatusCallbackFunc cb)
212 {
213 statusCallback_ = cb;
214 }
215
UpdateDownloadFinished(const std::string & url)216 void DashMpdDownloader::UpdateDownloadFinished(const std::string &url)
217 {
218 MEDIA_LOG_I("UpdateDownloadFinished:ondemandSegBase_=%{public}u", ondemandSegBase_);
219 if (ondemandSegBase_) {
220 ParseSidx();
221 } else {
222 ParseManifest();
223 }
224 }
225
GetInUseVideoStreamId() const226 int DashMpdDownloader::GetInUseVideoStreamId() const
227 {
228 for (uint32_t index = 0; index < streamDescriptions_.size(); index++) {
229 if (streamDescriptions_[index]->inUse_ && streamDescriptions_[index]->type_ == MediaAVCodec::MEDIA_TYPE_VID) {
230 return streamDescriptions_[index]->streamId_;
231 }
232 }
233 return -1;
234 }
235
GetNextSegmentByStreamId(int streamId,std::shared_ptr<DashSegment> & seg)236 DashMpdGetRet DashMpdDownloader::GetNextSegmentByStreamId(int streamId, std::shared_ptr<DashSegment> &seg)
237 {
238 MEDIA_LOG_I("GetNextSegmentByStreamId streamId:" PUBLIC_LOG_D32, streamId);
239 seg = nullptr;
240 DashMpdGetRet ret = DASH_MPD_GET_ERROR;
241 for (auto &streamDescription : streamDescriptions_) {
242 if (streamDescription->streamId_ != streamId) {
243 continue;
244 }
245
246 if (streamDescription->segsState_ == DASH_SEGS_STATE_FINISH) {
247 int64_t segmentIndex = (streamDescription->currentNumberSeq_ == -1) ? 0 :
248 streamDescription->currentNumberSeq_ - streamDescription->startNumberSeq_ + 1;
249 MEDIA_LOG_D("get segment index :" PUBLIC_LOG_D64 ", id:" PUBLIC_LOG_D32 ", seq:"
250 PUBLIC_LOG_D64, segmentIndex, streamDescription->streamId_, streamDescription->currentNumberSeq_);
251 if (segmentIndex >= 0 && (unsigned int) segmentIndex < streamDescription->mediaSegments_.size()) {
252 seg = streamDescription->mediaSegments_[segmentIndex];
253 streamDescription->currentNumberSeq_ = seg->numberSeq_;
254 MEDIA_LOG_D("after get segment index :"
255 PUBLIC_LOG_D64, streamDescription->currentNumberSeq_);
256 ret = DASH_MPD_GET_DONE;
257 } else {
258 ret = DASH_MPD_GET_FINISH;
259 }
260 } else {
261 ret = DASH_MPD_GET_UNDONE;
262 }
263 break;
264 }
265
266 return ret;
267 }
268
GetBreakPointSegment(int streamId,int64_t breakpoint,std::shared_ptr<DashSegment> & seg)269 DashMpdGetRet DashMpdDownloader::GetBreakPointSegment(int streamId, int64_t breakpoint,
270 std::shared_ptr<DashSegment> &seg)
271 {
272 MEDIA_LOG_I("GetBreakPointSegment streamId:" PUBLIC_LOG_D32 ", breakpoint:" PUBLIC_LOG_D64, streamId, breakpoint);
273 seg = nullptr;
274 DashMpdGetRet ret = DASH_MPD_GET_ERROR;
275 for (auto &streamDescription : streamDescriptions_) {
276 if (streamDescription->streamId_ != streamId) {
277 continue;
278 }
279
280 if (streamDescription->segsState_ != DASH_SEGS_STATE_FINISH) {
281 MEDIA_LOG_E("GetBreakPointSegment no segment list");
282 ret = DASH_MPD_GET_UNDONE;
283 break;
284 }
285
286 int64_t segmentDuration = 0;
287 for (unsigned int index = 0; index < streamDescription->mediaSegments_.size(); index++) {
288 if (segmentDuration + (int64_t)(streamDescription->mediaSegments_[index]->duration_) > breakpoint) {
289 seg = streamDescription->mediaSegments_[index];
290 break;
291 }
292 }
293
294 if (seg != nullptr) {
295 streamDescription->currentNumberSeq_ = seg->numberSeq_;
296 MEDIA_LOG_I("GetBreakPointSegment find segment index :"
297 PUBLIC_LOG_D64, streamDescription->currentNumberSeq_);
298 ret = DASH_MPD_GET_DONE;
299 } else {
300 MEDIA_LOG_W("GetBreakPointSegment all segment finish");
301 ret = DASH_MPD_GET_FINISH;
302 }
303 break;
304 }
305
306 return ret;
307 }
308
GetNextVideoStream(DashMpdBitrateParam & param,int & streamId)309 DashMpdGetRet DashMpdDownloader::GetNextVideoStream(DashMpdBitrateParam ¶m, int &streamId)
310 {
311 std::shared_ptr<DashStreamDescription> currentStream = nullptr;
312 std::shared_ptr<DashStreamDescription> destStream = nullptr;
313 bool isFirstSelect = true;
314 uint32_t maxGap = 0;
315 for (const auto &stream : streamDescriptions_) {
316 if (stream->type_ != MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
317 continue;
318 }
319
320 uint32_t tempGap = (stream->bandwidth_ > param.bitrate_) ?
321 (stream->bandwidth_ - param.bitrate_) : (param.bitrate_ - stream->bandwidth_);
322 if (isFirstSelect || (tempGap < maxGap)) {
323 isFirstSelect = false;
324 maxGap = tempGap;
325 destStream = stream;
326 }
327
328 if (stream->inUse_) {
329 currentStream = stream;
330 }
331 }
332
333 if (destStream == nullptr || currentStream == nullptr) {
334 MEDIA_LOG_E("switch to bandwidth:" PUBLIC_LOG_U32 ", can not find stream", param.bitrate_);
335 return DASH_MPD_GET_ERROR;
336 }
337
338 currentStream->inUse_ = false;
339 destStream->inUse_ = true;
340 streamId = destStream->streamId_;
341 if (param.position_ == -1) {
342 destStream->currentNumberSeq_ = currentStream->currentNumberSeq_;
343 } else {
344 destStream->currentNumberSeq_ = param.position_;
345 }
346
347 param.nextSegTime_ = GetSegTimeBySeq(currentStream->mediaSegments_, destStream->currentNumberSeq_);
348 MEDIA_LOG_I("select bitrate from type:" PUBLIC_LOG_D32 ", to type:" PUBLIC_LOG_D32 ", nextSegTime:"
349 PUBLIC_LOG_U32 ", bandwidth:" PUBLIC_LOG_U32 ", id:" PUBLIC_LOG_D32 ", width:"
350 PUBLIC_LOG_U32, currentStream->videoType_, destStream->videoType_, param.nextSegTime_,
351 destStream->bandwidth_, destStream->streamId_, destStream->width_);
352
353 DashMpdGetRet ret = GetSegmentsInNewStream(destStream);
354 if (ret == DASH_MPD_GET_DONE && param.nextSegTime_ > 0) {
355 UpdateCurrentNumberSeqByTime(destStream, param.nextSegTime_);
356 param.nextSegTime_ = 0;
357 }
358
359 return ret;
360 }
361
GetNextTrackStream(DashMpdTrackParam & param)362 DashMpdGetRet DashMpdDownloader::GetNextTrackStream(DashMpdTrackParam ¶m)
363 {
364 std::shared_ptr<DashStreamDescription> currentStream = nullptr;
365 std::shared_ptr<DashStreamDescription> destStream = nullptr;
366 for (const auto &stream : streamDescriptions_) {
367 if (stream->type_ != param.type_) {
368 continue;
369 }
370
371 if (stream->streamId_ == param.streamId_) {
372 destStream = stream;
373 MEDIA_LOG_I("switch to id:" PUBLIC_LOG_D32 ", lang:" PUBLIC_LOG_S,
374 stream->streamId_, stream->lang_.c_str());
375 }
376
377 if (stream->inUse_) {
378 currentStream = stream;
379 }
380 }
381
382 if (destStream == nullptr || currentStream == nullptr) {
383 MEDIA_LOG_E("switch to streamId:" PUBLIC_LOG_D32 ", can not find stream", param.streamId_);
384 return DASH_MPD_GET_ERROR;
385 }
386
387 currentStream->inUse_ = false;
388 destStream->inUse_ = true;
389
390 if (destStream->startNumberSeq_ != currentStream->startNumberSeq_) {
391 MEDIA_LOG_E("select track streamId:" PUBLIC_LOG_D32 " but seq:" PUBLIC_LOG_D64 " is not equal bitrate:"
392 PUBLIC_LOG_D32 ", seq:" PUBLIC_LOG_D64, destStream->streamId_, destStream->startNumberSeq_,
393 currentStream->streamId_, currentStream->startNumberSeq_);
394 }
395 if (param.position_ == -1) {
396 destStream->currentNumberSeq_ = currentStream->currentNumberSeq_;
397 } else {
398 destStream->currentNumberSeq_ = param.position_;
399 }
400
401 if (!param.isEnd_) {
402 destStream->currentNumberSeq_ -= 1;
403 if (destStream->currentNumberSeq_ < destStream->startNumberSeq_) {
404 destStream->currentNumberSeq_ = -1;
405 }
406 }
407
408 param.nextSegTime_ = GetSegTimeBySeq(currentStream->mediaSegments_, destStream->currentNumberSeq_);
409 MEDIA_LOG_I("select track current lang:" PUBLIC_LOG_S ", change to:" PUBLIC_LOG_S ",nextSegTime:"
410 PUBLIC_LOG_U32, currentStream->lang_.c_str(), destStream->lang_.c_str(), param.nextSegTime_);
411
412 DashMpdGetRet ret = GetSegmentsInNewStream(destStream);
413 if (ret == DASH_MPD_GET_DONE && param.nextSegTime_ > 0) {
414 UpdateCurrentNumberSeqByTime(destStream, param.nextSegTime_);
415 param.nextSegTime_ = 0;
416 }
417
418 return ret;
419 }
420
GetStreamByStreamId(int streamId)421 std::shared_ptr<DashStreamDescription> DashMpdDownloader::GetStreamByStreamId(int streamId)
422 {
423 auto iter = std::find_if(streamDescriptions_.begin(), streamDescriptions_.end(),
424 [&](const std::shared_ptr<DashStreamDescription> &stream) {
425 return stream->streamId_ == streamId;
426 });
427 if (iter == streamDescriptions_.end()) {
428 return nullptr;
429 }
430
431 return *iter;
432 }
433
GetUsingStreamByType(MediaAVCodec::MediaType type)434 std::shared_ptr<DashStreamDescription> DashMpdDownloader::GetUsingStreamByType(MediaAVCodec::MediaType type)
435 {
436 auto iter = std::find_if(streamDescriptions_.begin(), streamDescriptions_.end(),
437 [&](const std::shared_ptr<DashStreamDescription> &stream) {
438 return stream->type_ == type && stream->inUse_;
439 });
440 if (iter == streamDescriptions_.end()) {
441 return nullptr;
442 }
443
444 return *iter;
445 }
446
GetInitSegmentByStreamId(int streamId)447 std::shared_ptr<DashInitSegment> DashMpdDownloader::GetInitSegmentByStreamId(int streamId)
448 {
449 auto iter = std::find_if(streamDescriptions_.begin(), streamDescriptions_.end(),
450 [&](const std::shared_ptr<DashStreamDescription> &streamDescription) {
451 return streamDescription->streamId_ == streamId;
452 });
453 if (iter == streamDescriptions_.end()) {
454 return nullptr;
455 }
456 return (*iter)->initSegment_;
457 }
458
SetCurrentNumberSeqByStreamId(int streamId,int64_t numberSeq)459 void DashMpdDownloader::SetCurrentNumberSeqByStreamId(int streamId, int64_t numberSeq)
460 {
461 for (unsigned int index = 0; index < streamDescriptions_.size(); index++) {
462 if (streamDescriptions_[index]->streamId_ == streamId) {
463 streamDescriptions_[index]->currentNumberSeq_ = numberSeq;
464 MEDIA_LOG_I("SetCurrentNumberSeqByStreamId update id:" PUBLIC_LOG_D32 ", seq:"
465 PUBLIC_LOG_D64, streamId, numberSeq);
466 break;
467 }
468 }
469 }
470
UpdateCurrentNumberSeqByTime(const std::shared_ptr<DashStreamDescription> & streamDesc,uint32_t nextSegTime)471 void DashMpdDownloader::UpdateCurrentNumberSeqByTime(const std::shared_ptr<DashStreamDescription> &streamDesc,
472 uint32_t nextSegTime)
473 {
474 if (streamDesc == nullptr) {
475 return;
476 }
477
478 unsigned int previousSegsDuration = 0;
479 int64_t numberSeq = -1;
480 for (unsigned int index = 0; index < streamDesc->mediaSegments_.size(); index++) {
481 previousSegsDuration += streamDesc->mediaSegments_[index]->duration_;
482 // previousSegsDuration greater than nextSegTime 100ms, get this segment, otherwise find next segment to check
483 if (previousSegsDuration > nextSegTime && (previousSegsDuration - nextSegTime) > SEGMENT_DURATION_DELTA) {
484 MEDIA_LOG_I("UpdateSeqByTime find next seq:" PUBLIC_LOG_D64, streamDesc->mediaSegments_[index]->numberSeq_);
485 break;
486 }
487
488 numberSeq = streamDesc->mediaSegments_[index]->numberSeq_;
489 }
490
491 MEDIA_LOG_I("UpdateSeqByTime change current seq from:" PUBLIC_LOG_D64 " to:" PUBLIC_LOG_D64 ", nextSegTime:"
492 PUBLIC_LOG_U32, streamDesc->currentNumberSeq_, numberSeq, nextSegTime);
493 streamDesc->currentNumberSeq_ = numberSeq;
494 }
495
SetHdrStart(bool isHdrStart)496 void DashMpdDownloader::SetHdrStart(bool isHdrStart)
497 {
498 MEDIA_LOG_I("SetHdrStart:" PUBLIC_LOG_D32, isHdrStart);
499 isHdrStart_ = isHdrStart;
500 }
501
SetInitResolution(unsigned int width,unsigned int height)502 void DashMpdDownloader::SetInitResolution(unsigned int width, unsigned int height)
503 {
504 MEDIA_LOG_I("SetInitResolution, width:" PUBLIC_LOG_U32 ", height:" PUBLIC_LOG_U32, width, height);
505 if (width > 0 && height > 0) {
506 initResolution_ = width * height;
507 }
508 }
509
SetDefaultLang(const std::string & lang,MediaAVCodec::MediaType type)510 void DashMpdDownloader::SetDefaultLang(const std::string &lang, MediaAVCodec::MediaType type)
511 {
512 MEDIA_LOG_I("SetDefaultLang, lang:" PUBLIC_LOG_S ", type:" PUBLIC_LOG_D32, lang.c_str(), (int)type);
513 if (type == MediaAVCodec::MediaType::MEDIA_TYPE_AUD) {
514 defaultAudioLang_ = lang;
515 } else if (type == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
516 defaultSubtitleLang_ = lang;
517 }
518 }
519
SetInterruptState(bool isInterruptNeeded)520 void DashMpdDownloader::SetInterruptState(bool isInterruptNeeded)
521 {
522 isInterruptNeeded_ = isInterruptNeeded;
523 if (downloader_ != nullptr) {
524 downloader_->SetInterruptState(isInterruptNeeded);
525 }
526 }
527
GetUrl() const528 std::string DashMpdDownloader::GetUrl() const
529 {
530 return url_;
531 }
532
ParseManifest()533 void DashMpdDownloader::ParseManifest()
534 {
535 if (downloadContent_.length() == 0) {
536 MEDIA_LOG_I("ParseManifest content length is 0");
537 return;
538 }
539
540 mpdParser_->ParseMPD(downloadContent_.c_str(), downloadContent_.length());
541 mpdParser_->GetMPD(mpdInfo_);
542 if (mpdInfo_ != nullptr) {
543 mpdManager_->SetMpdInfo(mpdInfo_, url_);
544 mpdManager_->GetDuration(&duration_);
545 SetOndemandSegBase();
546 GetStreamsInfoInMpd();
547 ChooseStreamToPlay(MediaAVCodec::MediaType::MEDIA_TYPE_VID);
548 ChooseStreamToPlay(MediaAVCodec::MediaType::MEDIA_TYPE_AUD);
549 ChooseStreamToPlay(MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE);
550 if (ondemandSegBase_) {
551 PutStreamToDownload();
552 ProcessDrmInfos();
553 return;
554 }
555
556 if (callback_ != nullptr) {
557 callback_->OnMpdInfoUpdate(DASH_MPD_EVENT_STREAM_INIT);
558 }
559
560 ProcessDrmInfos();
561 notifyOpenOk_ = true;
562 }
563 }
564
GetDrmInfos(std::vector<DashDrmInfo> & drmInfos)565 void DashMpdDownloader::GetDrmInfos(std::vector<DashDrmInfo>& drmInfos)
566 {
567 std::list<DashPeriodInfo*> periods = mpdInfo_->periodInfoList_;
568 for (auto &periodInfo : periods) {
569 if (periodInfo == nullptr) {
570 continue;
571 }
572 std::string periodDrmId{"PeriodId:"};
573 periodDrmId.append(periodInfo->id_);
574 GetAdpDrmInfos(drmInfos, periodInfo, periodDrmId);
575 }
576 }
577
GetAdpDrmInfos(std::vector<DashDrmInfo> & drmInfos,DashPeriodInfo * const & periodInfo,const std::string & periodDrmId)578 void DashMpdDownloader::GetAdpDrmInfos(std::vector<DashDrmInfo> &drmInfos, DashPeriodInfo *const &periodInfo,
579 const std::string &periodDrmId)
580 {
581 DashList<DashAdptSetInfo*> adptSetList = periodInfo->adptSetList_;
582 for (const auto &adptSetInfo : adptSetList) {
583 if (adptSetInfo == nullptr) {
584 continue;
585 }
586
587 std::string adptSetDrmId = periodDrmId;
588 adptSetDrmId.append(":AdptSetId:");
589 adptSetDrmId.append(std::to_string(adptSetInfo->id_));
590 GetDrmInfos(adptSetDrmId, adptSetInfo->commonAttrsAndElements_.contentProtectionList_, drmInfos);
591 DashList<DashRepresentationInfo*> representationList = adptSetInfo->representationList_;
592 for (auto &representationInfo : representationList) {
593 if (representationInfo == nullptr) {
594 continue;
595 }
596 std::string representationDrmId = adptSetDrmId;
597 representationDrmId.append(":RepresentationId:");
598 representationDrmId.append(representationInfo->id_);
599 GetDrmInfos(representationDrmId, representationInfo->commonAttrsAndElements_.contentProtectionList_,
600 drmInfos);
601 }
602 }
603 }
604
ProcessDrmInfos()605 void DashMpdDownloader::ProcessDrmInfos()
606 {
607 std::vector<DashDrmInfo> drmInfos;
608 GetDrmInfos(drmInfos);
609
610 std::multimap<std::string, std::vector<uint8_t>> drmInfoMap;
611 for (const auto &drmInfo: drmInfos) {
612 bool isReported = std::any_of(localDrmInfos_.begin(), localDrmInfos_.end(),
613 [&](const DashDrmInfo &localDrmInfo) {
614 return drmInfo.uuid_ == localDrmInfo.uuid_ && drmInfo.pssh_ == localDrmInfo.pssh_;
615 });
616 if (isReported) {
617 continue;
618 }
619
620 std::string psshString = drmInfo.pssh_;
621 uint8_t pssh[2048]; // 2048: pssh len
622 uint32_t psshSize = 2048; // 2048: pssh len
623 if (Base64Utils::Base64Decode(reinterpret_cast<const uint8_t *>(psshString.c_str()),
624 static_cast<uint32_t>(psshString.length()), pssh, &psshSize)) {
625 uint32_t uuidSize = 16; // 16: uuid len
626 if (psshSize < DRM_UUID_OFFSET + uuidSize) {
627 continue;
628 }
629
630 uint8_t uuid[16]; // 16: uuid len
631 errno_t ret = memcpy_s(uuid, sizeof(uuid), pssh + DRM_UUID_OFFSET, uuidSize);
632 if (ret != EOK) {
633 MEDIA_LOG_W("fetch uuid from pssh error, drmId " PUBLIC_LOG_S, drmInfo.drmId_.c_str());
634 continue;
635 }
636 std::stringstream ssConverter;
637 std::string uuidString;
638 for (uint32_t i = 0; i < uuidSize; i++) {
639 ssConverter << std::hex << std::setfill('0') << std::setw(2) << static_cast<int32_t>(uuid[i]); // 2:w
640 uuidString = ssConverter.str();
641 }
642 drmInfoMap.insert({uuidString, std::vector<uint8_t>(pssh, pssh + psshSize)});
643 localDrmInfos_.emplace_back(drmInfo);
644 } else {
645 MEDIA_LOG_W("Base64Decode pssh error, drmId " PUBLIC_LOG_S, drmInfo.drmId_.c_str());
646 }
647 }
648
649 if (callback_ != nullptr) {
650 callback_->OnDrmInfoChanged(drmInfoMap);
651 }
652 }
653
GetDrmInfos(const std::string & drmId,const DashList<DashDescriptor * > & contentProtections,std::vector<DashDrmInfo> & drmInfoList)654 void DashMpdDownloader::GetDrmInfos(const std::string &drmId, const DashList<DashDescriptor *> &contentProtections,
655 std::vector<DashDrmInfo> &drmInfoList)
656 {
657 for (const auto &contentProtection : contentProtections) {
658 if (contentProtection == nullptr) {
659 continue;
660 }
661
662 std::string schemeIdUrl = contentProtection->schemeIdUrl_;
663 size_t uuidPos = schemeIdUrl.find(DRM_URN_UUID_PREFIX);
664 if (uuidPos != std::string::npos) {
665 std::string urnUuid = DRM_URN_UUID_PREFIX;
666 std::string systemId = schemeIdUrl.substr(uuidPos + urnUuid.length());
667 auto elementIt = contentProtection->elementMap_.find(MPD_LABEL_PSSH);
668 if (elementIt != contentProtection->elementMap_.end()) {
669 DashDrmInfo drmInfo = {drmId, systemId, elementIt->second};
670 drmInfoList.emplace_back(drmInfo);
671 }
672 }
673 }
674 }
675
ParseSidx()676 void DashMpdDownloader::ParseSidx()
677 {
678 if (downloadContent_.length() == 0 || currentDownloadStream_ == nullptr ||
679 currentDownloadStream_->indexSegment_ == nullptr) {
680 MEDIA_LOG_I("ParseSidx content length is 0 or stream is nullptr");
681 return;
682 }
683
684 std::string sidxContent = downloadContent_;
685 if (CheckToDownloadSidxWithInitSeg(currentDownloadStream_)) {
686 currentDownloadStream_->initSegment_->content_ = downloadContent_;
687 currentDownloadStream_->initSegment_->isDownloadFinish_ = true;
688 MEDIA_LOG_I("ParseSidx update init segment content size is "
689 PUBLIC_LOG_ZU, currentDownloadStream_->initSegment_->content_.size());
690 int64_t initLen = currentDownloadStream_->indexSegment_->indexRangeBegin_ -
691 currentDownloadStream_->initSegment_->rangeBegin_;
692 if (initLen >= 0 && (unsigned int)initLen < downloadContent_.size()) {
693 sidxContent = downloadContent_.substr((unsigned int)initLen);
694 MEDIA_LOG_I("ParseSidx update sidx segment content size is " PUBLIC_LOG_ZU, sidxContent.size());
695 }
696 }
697
698 std::list<std::shared_ptr<SubSegmentIndex>> subSegIndexList;
699 int32_t parseRet = SidxBoxParser::ParseSidxBox(const_cast<char *>(sidxContent.c_str()), sidxContent.length(),
700 currentDownloadStream_->indexSegment_->indexRangeEnd_,
701 subSegIndexList);
702 if (parseRet != 0) {
703 MEDIA_LOG_E("sidx box parse error");
704 return;
705 }
706
707 BuildDashSegment(subSegIndexList);
708 currentDownloadStream_->segsState_ = DASH_SEGS_STATE_FINISH;
709 if (!notifyOpenOk_) {
710 if (!PutStreamToDownload()) {
711 if (callback_ != nullptr) {
712 callback_->OnMpdInfoUpdate(DASH_MPD_EVENT_STREAM_INIT);
713 }
714
715 notifyOpenOk_ = true;
716 }
717 } else {
718 if (callback_ != nullptr) {
719 callback_->OnMpdInfoUpdate(DASH_MPD_EVENT_PARSE_OK);
720 }
721 }
722 }
723
BuildDashSegment(std::list<std::shared_ptr<SubSegmentIndex>> & subSegIndexList) const724 void DashMpdDownloader::BuildDashSegment(std::list<std::shared_ptr<SubSegmentIndex>> &subSegIndexList) const
725 {
726 uint64_t segDurSum = 0; // the sum of segment duration, not devide timescale
727 uint64_t segAddDuration = 0; // add all segments duration(ms) before current segment
728 uint32_t timeScale = 1;
729 int64_t segSeq = currentDownloadStream_->startNumberSeq_;
730 for (const auto &subSegIndex : subSegIndexList) {
731 timeScale = (subSegIndex->timeScale_ > 0) ? subSegIndex->timeScale_ : 1;
732 uint64_t durationMS = (static_cast<uint64_t>(subSegIndex->duration_) * S_2_MS) / timeScale;
733 segDurSum += subSegIndex->duration_;
734 uint64_t segDurMsSum = (segDurSum * S_2_MS) / timeScale;
735 if (segDurMsSum >= UINT_MAX) {
736 MEDIA_LOG_W("segDurMsSum is too large: " PUBLIC_LOG_U64 ", timeScale: "
737 PUBLIC_LOG_U32, segDurMsSum, timeScale);
738 break;
739 }
740
741 if (segDurMsSum > segAddDuration) {
742 durationMS = segDurMsSum - segAddDuration;
743 }
744
745 segAddDuration += durationMS;
746
747 DashSegment srcSegment;
748 srcSegment.streamId_ = currentDownloadStream_->streamId_;
749 srcSegment.bandwidth_ = currentDownloadStream_->bandwidth_;
750 srcSegment.duration_ = (uint32_t)durationMS;
751 srcSegment.startNumberSeq_ = currentDownloadStream_->startNumberSeq_;
752 srcSegment.numberSeq_ = segSeq++;
753 srcSegment.startRangeValue_ = subSegIndex->startPos_;
754 srcSegment.endRangeValue_ = subSegIndex->endPos_;
755 srcSegment.url_ = currentDownloadStream_->indexSegment_->url_; // only store url in stream in Dash On-Demand
756 srcSegment.byteRange_ = "";
757 if (DASH_SEGMENT_INIT_FAILED == AddOneSegment(srcSegment, currentDownloadStream_)) {
758 MEDIA_LOG_E("ParseSidx AddOneSegment is failed");
759 }
760 }
761
762 if (currentDownloadStream_->mediaSegments_.size() > 0) {
763 std::shared_ptr<DashSegment> lastSegment = currentDownloadStream_->mediaSegments_[
764 currentDownloadStream_->mediaSegments_.size() - 1];
765 if (lastSegment != nullptr && mpdInfo_ != nullptr && mpdInfo_->type_ == DashType::DASH_TYPE_STATIC) {
766 lastSegment->isLast_ = true;
767 }
768 }
769 }
770
OpenStream(std::shared_ptr<DashStreamDescription> stream)771 void DashMpdDownloader::OpenStream(std::shared_ptr<DashStreamDescription> stream)
772 {
773 stream->segsState_ = DASH_SEGS_STATE_PARSING;
774 currentDownloadStream_ = stream;
775 int64_t startRange = stream->indexSegment_->indexRangeBegin_;
776 int64_t endRange = stream->indexSegment_->indexRangeEnd_;
777 // exist init segment, download together
778 if (CheckToDownloadSidxWithInitSeg(stream)) {
779 MEDIA_LOG_I("update range begin from " PUBLIC_LOG_D64 " to "
780 PUBLIC_LOG_D64, startRange, stream->initSegment_->rangeBegin_);
781 startRange = stream->initSegment_->rangeBegin_;
782 }
783 DoOpen(stream->indexSegment_->url_, startRange, endRange);
784 }
785
DoOpen(const std::string & url,int64_t startRange,int64_t endRange)786 void DashMpdDownloader::DoOpen(const std::string& url, int64_t startRange, int64_t endRange)
787 {
788 downloadContent_.clear();
789 auto realStatusCallback = [this](DownloadStatus &&status, std::shared_ptr<Downloader> &downloader,
790 std::shared_ptr<DownloadRequest> &request) {
791 if (statusCallback_ != nullptr) {
792 statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
793 }
794 };
795
796 bool requestWholeFile = true;
797 if (startRange > 0 || endRange > 0) {
798 requestWholeFile = false;
799 }
800
801 MEDIA_LOG_I("DoOpen:start=%{public}lld end=%{public}lld", (long long) startRange, (long long) endRange);
802 RequestInfo mediaSource;
803 mediaSource.url = url;
804 mediaSource.timeoutMs = MPD_HTTP_TIME_OUT_MS;
805 downloadRequest_ = std::make_shared<DownloadRequest>(dataSave_, realStatusCallback, mediaSource, requestWholeFile);
806 auto downloadDoneCallback = [this](const std::string &url, const std::string &location) {
807 UpdateDownloadFinished(url);
808 };
809 downloadRequest_->SetDownloadDoneCb(downloadDoneCallback);
810 downloadRequest_->SetRequestProtocolType(RequestProtocolType::DASH);
811 if (!requestWholeFile) {
812 downloadRequest_->SetRangePos(startRange, endRange);
813 }
814 downloader_->Download(downloadRequest_, -1); // -1
815 downloader_->Start();
816 }
817
SaveData(uint8_t * data,uint32_t len,bool notBlock)818 uint32_t DashMpdDownloader::SaveData(uint8_t* data, uint32_t len, bool notBlock)
819 {
820 MEDIA_LOG_D("SaveData:size=%{public}u len=%{public}u", (unsigned int)downloadContent_.size(), len);
821 downloadContent_.append(reinterpret_cast<const char*>(data), len);
822 return len;
823 }
824
SetMpdCallback(DashMpdCallback * callback)825 void DashMpdDownloader::SetMpdCallback(DashMpdCallback *callback)
826 {
827 callback_ = callback;
828 }
829
GetDuration() const830 int64_t DashMpdDownloader::GetDuration() const
831 {
832 MEDIA_LOG_I("GetDuration " PUBLIC_LOG_U32, duration_);
833 return (duration_ > 0) ? ((int64_t)duration_ * MS_2_NS) : 0;
834 }
835
GetSeekable() const836 Seekable DashMpdDownloader::GetSeekable() const
837 {
838 // need wait mpdInfo_ not null
839 size_t times = 0;
840 while (times < RETRY_TIMES && !isInterruptNeeded_) {
841 if (mpdInfo_ != nullptr && notifyOpenOk_) {
842 break;
843 }
844 OSAL::SleepFor(SLEEP_TIME);
845 times++;
846 }
847
848 if (times >= RETRY_TIMES || isInterruptNeeded_) {
849 MEDIA_LOG_I("GetSeekable INVALID");
850 return Seekable::INVALID;
851 }
852
853 MEDIA_LOG_I("GetSeekable end");
854 return mpdInfo_->type_ == DashType::DASH_TYPE_STATIC ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
855 }
856
GetBitRates() const857 std::vector<uint32_t> DashMpdDownloader::GetBitRates() const
858 {
859 std::vector<uint32_t> bitRates;
860 for (const auto &item : streamDescriptions_) {
861 if (item->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID && item->bandwidth_ > 0) {
862 bitRates.push_back(item->bandwidth_);
863 }
864 }
865 return bitRates;
866 }
867
GetBitRatesByHdr(bool isHdr) const868 std::vector<uint32_t> DashMpdDownloader::GetBitRatesByHdr(bool isHdr) const
869 {
870 std::vector<uint32_t> bitRates;
871 for (const auto &item : streamDescriptions_) {
872 if (item->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID &&
873 item->bandwidth_ > 0 &&
874 (isHdr == (item->videoType_ != DASH_VIDEO_TYPE_SDR))) {
875 bitRates.push_back(item->bandwidth_);
876 }
877 }
878 return bitRates;
879 }
880
SeekToTs(int streamId,int64_t seekTime,std::shared_ptr<DashSegment> & seg) const881 int64_t DashMpdDownloader::SeekToTs(int streamId, int64_t seekTime, std::shared_ptr<DashSegment> &seg) const
882 {
883 seg = nullptr;
884 std::vector<std::shared_ptr<DashSegment>> mediaSegments;
885 std::shared_ptr<DashStreamDescription> streamDescription;
886 for (const auto &index : streamDescriptions_) {
887 streamDescription = index;
888 if (streamDescription != nullptr && streamDescription->streamId_ == streamId &&
889 streamDescription->segsState_ == DASH_SEGS_STATE_FINISH) {
890 mediaSegments = streamDescription->mediaSegments_;
891 break;
892 }
893 }
894
895 int64_t totalDuration = 0;
896 if (!mediaSegments.empty()) {
897 for (const auto &mediaSegment : mediaSegments) {
898 if (mediaSegment == nullptr) {
899 continue;
900 }
901
902 totalDuration += static_cast<int64_t>(mediaSegment->duration_);
903 if (totalDuration > seekTime) {
904 seg = mediaSegment;
905 MEDIA_LOG_I("Dash SeekToTs segment totalDuration:" PUBLIC_LOG_D64 ", segNum:"
906 PUBLIC_LOG_D64 ", duration:" PUBLIC_LOG_U32,
907 totalDuration, mediaSegment->numberSeq_, mediaSegment->duration_);
908 totalDuration -= static_cast<int64_t>(mediaSegment->duration_);
909 break;
910 }
911 }
912 }
913 return totalDuration;
914 }
915
916 /**
917 * @brief get segments in Period with SegmentTemplate or SegmentList or BaseUrl
918 *
919 * @param periodInfo current Period
920 * @param adptSetInfo current AdptSet
921 * @param periodBaseUrl Mpd.BaseUrl
922 * @param streamDesc stream description
923 *
924 * @return failed success undo
925 */
GetSegmentsByPeriodInfo(DashPeriodInfo * periodInfo,DashAdptSetInfo * adptSetInfo,std::string & periodBaseUrl,std::shared_ptr<DashStreamDescription> streamDesc)926 DashSegmentInitValue DashMpdDownloader::GetSegmentsByPeriodInfo(DashPeriodInfo *periodInfo,
927 DashAdptSetInfo *adptSetInfo,
928 std::string &periodBaseUrl,
929 std::shared_ptr<DashStreamDescription> streamDesc)
930 {
931 DashSegmentInitValue initVal;
932 // get segments from Period.SegmentTemplate
933 if (periodInfo->periodSegTmplt_ != nullptr && periodInfo->periodSegTmplt_->segTmpltMedia_.length() > 0) {
934 DashAppendBaseUrl(periodBaseUrl, periodInfo->baseUrl_);
935
936 std::string representationId;
937 // get Representation@id in the chosen AdaptationSet
938 if (adptSetInfo != nullptr && streamDesc->bandwidth_ > 0) {
939 DashRepresentationInfo *repInfo = GetRepresentationFromAdptSet(adptSetInfo,
940 streamDesc->representationIndex_);
941 if (repInfo != nullptr) {
942 representationId = repInfo->id_;
943 }
944 }
945
946 initVal = GetSegmentsWithSegTemplate(periodInfo->periodSegTmplt_, representationId, streamDesc);
947 } else if (periodInfo->periodSegList_ != nullptr && periodInfo->periodSegList_->segmentUrl_.size() > 0) {
948 // get segments from Period.SegmentList
949 DashAppendBaseUrl(periodBaseUrl, periodInfo->baseUrl_);
950 initVal = GetSegmentsWithSegList(periodInfo->periodSegList_, periodBaseUrl, streamDesc);
951 } else if (periodInfo->baseUrl_.size() > 0) {
952 // get segments fromn Period.BaseUrl
953 initVal = GetSegmentsWithBaseUrl(periodInfo->baseUrl_, streamDesc);
954 } else {
955 initVal = DASH_SEGMENT_INIT_UNDO;
956 }
957
958 return initVal;
959 }
960
SetOndemandSegBase()961 void DashMpdDownloader::SetOndemandSegBase()
962 {
963 for (const auto &periodInfo : mpdInfo_->periodInfoList_) {
964 if (SetOndemandSegBase(periodInfo->adptSetList_)) {
965 break;
966 }
967 }
968
969 MEDIA_LOG_I("dash onDemandSegBase is " PUBLIC_LOG_D32, ondemandSegBase_);
970 }
971
SetOndemandSegBase(std::list<DashAdptSetInfo * > adptSetList)972 bool DashMpdDownloader::SetOndemandSegBase(std::list<DashAdptSetInfo*> adptSetList)
973 {
974 for (const auto &adptSetInfo : adptSetList) {
975 if (adptSetInfo->representationList_.size() == 0) {
976 if (adptSetInfo->adptSetSegBase_ != nullptr && adptSetInfo->adptSetSegBase_->indexRange_.size() > 0) {
977 ondemandSegBase_ = true;
978 return true;
979 }
980 } else {
981 if (SetOndemandSegBase(adptSetInfo->representationList_)) {
982 return true;
983 }
984 }
985 }
986
987 return false;
988 }
989
SetOndemandSegBase(std::list<DashRepresentationInfo * > repList)990 bool DashMpdDownloader::SetOndemandSegBase(std::list<DashRepresentationInfo*> repList)
991 {
992 for (const auto &rep : repList) {
993 if (rep->representationSegList_ != nullptr || rep->representationSegTmplt_ != nullptr) {
994 MEDIA_LOG_I("dash representation contain segmentlist or template");
995 ondemandSegBase_ = false;
996 return true;
997 }
998
999 if (rep->representationSegBase_ != nullptr && rep->representationSegBase_->indexRange_.size() > 0) {
1000 MEDIA_LOG_I("dash representation contain indexRange");
1001 ondemandSegBase_ = true;
1002 return true;
1003 }
1004 }
1005
1006 return false;
1007 }
1008
CheckToDownloadSidxWithInitSeg(std::shared_ptr<DashStreamDescription> streamDesc)1009 bool DashMpdDownloader::CheckToDownloadSidxWithInitSeg(std::shared_ptr<DashStreamDescription> streamDesc)
1010 {
1011 if (streamDesc->initSegment_ != nullptr &&
1012 streamDesc->initSegment_->url_.compare(streamDesc->indexSegment_->url_) == 0 &&
1013 streamDesc->indexSegment_->indexRangeBegin_ > streamDesc->initSegment_->rangeEnd_) {
1014 return true;
1015 }
1016
1017 return false;
1018 }
1019
GetStreamsInfoInMpd()1020 bool DashMpdDownloader::GetStreamsInfoInMpd()
1021 {
1022 if (mpdInfo_ == nullptr) {
1023 return false;
1024 }
1025
1026 mpdManager_->SetMpdInfo(mpdInfo_, url_);
1027 std::string mpdBaseUrl = mpdManager_->GetBaseUrl();
1028 std::list<DashPeriodInfo*> periods = mpdInfo_->periodInfoList_;
1029 unsigned int periodIndex = 0;
1030 for (std::list<DashPeriodInfo*>::iterator it = periods.begin(); it != periods.end(); ++it, ++periodIndex) {
1031 DashPeriodInfo *period = *it;
1032 if (period == nullptr) {
1033 continue;
1034 }
1035
1036 GetStreamsInfoInPeriod(period, periodIndex, mpdBaseUrl);
1037 }
1038
1039 int size = static_cast<int>(streamDescriptions_.size());
1040 for (int index = 0; index < size; index++) {
1041 streamDescriptions_[index]->streamId_ = index;
1042 std::shared_ptr<DashInitSegment> initSegment = streamDescriptions_[index]->initSegment_;
1043 if (initSegment != nullptr) {
1044 initSegment->streamId_ = index;
1045 }
1046 }
1047
1048 return true;
1049 }
1050
GetStreamsInfoInPeriod(DashPeriodInfo * periodInfo,unsigned int periodIndex,const std::string & mpdBaseUrl)1051 void DashMpdDownloader::GetStreamsInfoInPeriod(DashPeriodInfo *periodInfo, unsigned int periodIndex,
1052 const std::string &mpdBaseUrl)
1053 {
1054 periodManager_->SetPeriodInfo(periodInfo);
1055 DashStreamDescription streamDesc;
1056 streamDesc.duration_ = (periodInfo->duration_ > 0) ? periodInfo->duration_ : duration_;
1057 streamDesc.periodIndex_ = periodIndex;
1058 std::string periodBaseUrl = mpdBaseUrl;
1059 DashAppendBaseUrl(periodBaseUrl, periodInfo->baseUrl_);
1060
1061 if (periodInfo->adptSetList_.size() == 0) {
1062 streamDesc.startNumberSeq_ = GetStartNumber(periodInfo);
1063 // no adaptationset in period, store as video stream
1064 std::shared_ptr<DashStreamDescription> desc = std::make_shared<DashStreamDescription>(streamDesc);
1065
1066 GetInitSegFromPeriod(periodBaseUrl, "", desc);
1067 if (ondemandSegBase_ && periodInfo->periodSegBase_ != nullptr &&
1068 periodInfo->periodSegBase_->indexRange_.size() > 0) {
1069 desc->indexSegment_ = std::make_shared<DashIndexSegment>();
1070 desc->indexSegment_->url_ = periodBaseUrl;
1071 DashParseRange(periodInfo->periodSegBase_->indexRange_, desc->indexSegment_->indexRangeBegin_,
1072 desc->indexSegment_->indexRangeEnd_);
1073 }
1074 streamDescriptions_.push_back(desc);
1075 return;
1076 }
1077
1078 std::vector<DashAdptSetInfo*> adptSetVector;
1079 DashAdptSetInfo *adptSetInfo = nullptr;
1080 for (int32_t type = MediaAVCodec::MediaType::MEDIA_TYPE_AUD;
1081 type <= MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE; type++) {
1082 streamDesc.type_ = (MediaAVCodec::MediaType)type;
1083 periodManager_->GetAdptSetsByStreamType(adptSetVector, streamDesc.type_);
1084 if (adptSetVector.size() == 0) {
1085 MEDIA_LOG_I("Get streamType " PUBLIC_LOG_D32 " in period " PUBLIC_LOG_U32 " size is 0", type, periodIndex);
1086 continue;
1087 }
1088
1089 for (unsigned int adptSetIndex = 0; adptSetIndex < adptSetVector.size(); adptSetIndex++) {
1090 streamDesc.adptSetIndex_ = adptSetIndex;
1091 adptSetInfo = adptSetVector[adptSetIndex];
1092 GetStreamsInfoInAdptSet(adptSetInfo, periodBaseUrl, streamDesc);
1093 }
1094 }
1095 }
1096
GetStreamsInfoInAdptSet(DashAdptSetInfo * adptSetInfo,const std::string & periodBaseUrl,DashStreamDescription & streamDesc)1097 void DashMpdDownloader::GetStreamsInfoInAdptSet(DashAdptSetInfo *adptSetInfo, const std::string &periodBaseUrl,
1098 DashStreamDescription &streamDesc)
1099 {
1100 streamDesc.width_ = adptSetInfo->commonAttrsAndElements_.width_;
1101 streamDesc.height_ = adptSetInfo->commonAttrsAndElements_.height_;
1102 streamDesc.lang_ = adptSetInfo->lang_;
1103 std::string adptSetBaseUrl = periodBaseUrl;
1104 DashAppendBaseUrl(adptSetBaseUrl, adptSetInfo->baseUrl_);
1105 adptSetManager_->SetAdptSetInfo(adptSetInfo);
1106 if (adptSetManager_->IsHdr()) {
1107 streamDesc.videoType_ = DASH_VIDEO_TYPE_HDR_10;
1108 } else {
1109 streamDesc.videoType_ = DASH_VIDEO_TYPE_SDR;
1110 }
1111 MEDIA_LOG_D("GetStreamsInfoInAdptSet hdrType " PUBLIC_LOG_U32, streamDesc.videoType_);
1112
1113 std::list<DashRepresentationInfo*> repList = adptSetInfo->representationList_;
1114 if (repList.size() == 0) {
1115 MEDIA_LOG_I("representation count is 0 in adptset index " PUBLIC_LOG_U32, streamDesc.adptSetIndex_);
1116 streamDesc.startNumberSeq_ = GetStartNumber(adptSetInfo);
1117 std::shared_ptr<DashStreamDescription> desc = std::make_shared<DashStreamDescription>(streamDesc);
1118 if (!GetInitSegFromAdptSet(adptSetBaseUrl, "", desc)) {
1119 GetInitSegFromPeriod(periodBaseUrl, "", desc);
1120 }
1121
1122 if (ondemandSegBase_ && adptSetInfo->adptSetSegBase_ != nullptr &&
1123 adptSetInfo->adptSetSegBase_->indexRange_.size() > 0) {
1124 desc->indexSegment_ = std::make_shared<DashIndexSegment>();
1125 desc->indexSegment_->url_ = adptSetBaseUrl;
1126 DashParseRange(adptSetInfo->adptSetSegBase_->indexRange_, desc->indexSegment_->indexRangeBegin_,
1127 desc->indexSegment_->indexRangeEnd_);
1128 }
1129 streamDescriptions_.push_back(desc);
1130 return;
1131 }
1132
1133 GetStreamDescriptions(periodBaseUrl, streamDesc, adptSetBaseUrl, repList);
1134 }
1135
GetStreamDescriptions(const std::string & periodBaseUrl,DashStreamDescription & streamDesc,const std::string & adptSetBaseUrl,std::list<DashRepresentationInfo * > & repList)1136 void DashMpdDownloader::GetStreamDescriptions(const std::string &periodBaseUrl, DashStreamDescription &streamDesc,
1137 const std::string &adptSetBaseUrl,
1138 std::list<DashRepresentationInfo *> &repList)
1139 {
1140 std::string repBaseUrl;
1141 unsigned int repIndex = 0;
1142 DashVideoType defaultVideoType = streamDesc.videoType_;
1143 for (std::list<DashRepresentationInfo*>::iterator it = repList.begin(); it != repList.end(); ++it, ++repIndex) {
1144 if (*it == nullptr) {
1145 continue;
1146 }
1147
1148 repBaseUrl = adptSetBaseUrl;
1149 streamDesc.representationIndex_ = repIndex;
1150 streamDesc.startNumberSeq_ = GetStartNumber(*it);
1151 streamDesc.bandwidth_ = (*it)->bandwidth_;
1152 if ((*it)->commonAttrsAndElements_.width_ > 0) {
1153 streamDesc.width_ = (*it)->commonAttrsAndElements_.width_;
1154 }
1155
1156 if ((*it)->commonAttrsAndElements_.height_ > 0) {
1157 streamDesc.height_ = (*it)->commonAttrsAndElements_.height_;
1158 }
1159
1160 if (defaultVideoType != DASH_VIDEO_TYPE_SDR &&
1161 (*it)->commonAttrsAndElements_.cuvvVersion_.find("cuvv.") != std::string::npos) {
1162 streamDesc.videoType_ = DASH_VIDEO_TYPE_HDR_VIVID;
1163 MEDIA_LOG_I("current stream is hdr vivid, band:" PUBLIC_LOG_U32, streamDesc.bandwidth_);
1164 } else {
1165 streamDesc.videoType_ = defaultVideoType;
1166 }
1167
1168 std::shared_ptr<DashStreamDescription> desc = std::make_shared<DashStreamDescription>(streamDesc);
1169 representationManager_->SetRepresentationInfo(*it);
1170 DashAppendBaseUrl(repBaseUrl, (*it)->baseUrl_);
1171
1172 if (!GetInitSegFromRepresentation(repBaseUrl, (*it)->id_, desc)) {
1173 if (!GetInitSegFromAdptSet(adptSetBaseUrl, (*it)->id_, desc)) {
1174 GetInitSegFromPeriod(periodBaseUrl, (*it)->id_, desc);
1175 }
1176 }
1177
1178 if (ondemandSegBase_ &&
1179 (*it)->representationSegBase_ != nullptr &&
1180 (*it)->representationSegBase_->indexRange_.size() > 0) {
1181 desc->indexSegment_ = std::make_shared<DashIndexSegment>();
1182 desc->indexSegment_->url_ = repBaseUrl;
1183 DashParseRange((*it)->representationSegBase_->indexRange_, desc->indexSegment_->indexRangeBegin_,
1184 desc->indexSegment_->indexRangeEnd_);
1185 }
1186 MEDIA_LOG_I("add stream band:" PUBLIC_LOG_U32 ", hdr: " PUBLIC_LOG_D32,
1187 streamDesc.bandwidth_, streamDesc.videoType_);
1188 streamDescriptions_.push_back(desc);
1189 }
1190 }
1191
GetResolutionDelta(unsigned int width,unsigned int height)1192 unsigned int DashMpdDownloader::GetResolutionDelta(unsigned int width, unsigned int height)
1193 {
1194 unsigned int resolution = width * height;
1195 if (resolution > initResolution_) {
1196 return resolution - initResolution_;
1197 } else {
1198 return initResolution_ - resolution;
1199 }
1200 }
1201
IsChoosedVideoStream(const std::shared_ptr<DashStreamDescription> & choosedStream,const std::shared_ptr<DashStreamDescription> & currentStream)1202 bool DashMpdDownloader::IsChoosedVideoStream(const std::shared_ptr<DashStreamDescription> &choosedStream,
1203 const std::shared_ptr<DashStreamDescription> ¤tStream)
1204 {
1205 if (choosedStream == nullptr ||
1206 (initResolution_ == 0 && choosedStream->bandwidth_ > currentStream->bandwidth_) ||
1207 IsNearToInitResolution(choosedStream, currentStream)) {
1208 return true;
1209 }
1210 return false;
1211 }
1212
IsNearToInitResolution(const std::shared_ptr<DashStreamDescription> & choosedStream,const std::shared_ptr<DashStreamDescription> & currentStream)1213 bool DashMpdDownloader::IsNearToInitResolution(const std::shared_ptr<DashStreamDescription> &choosedStream,
1214 const std::shared_ptr<DashStreamDescription> ¤tStream)
1215 {
1216 if (choosedStream == nullptr || currentStream == nullptr || initResolution_ == 0) {
1217 return false;
1218 }
1219
1220 unsigned int choosedDelta = GetResolutionDelta(choosedStream->width_, choosedStream->height_);
1221 unsigned int currentDelta = GetResolutionDelta(currentStream->width_, currentStream->height_);
1222 return (currentDelta < choosedDelta)
1223 || (currentDelta == choosedDelta && currentStream->bandwidth_ < choosedStream->bandwidth_);
1224 }
1225
IsLangMatch(const std::string & lang,MediaAVCodec::MediaType type)1226 bool DashMpdDownloader::IsLangMatch(const std::string &lang, MediaAVCodec::MediaType type)
1227 {
1228 if (type == MediaAVCodec::MediaType::MEDIA_TYPE_AUD &&
1229 defaultAudioLang_.length() > 0) {
1230 if (defaultAudioLang_.compare(lang) == 0) {
1231 return true;
1232 } else {
1233 return false;
1234 }
1235 } else if (type == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE &&
1236 defaultSubtitleLang_.length() > 0) {
1237 if (defaultSubtitleLang_.compare(lang) == 0) {
1238 return true;
1239 } else {
1240 return false;
1241 }
1242 }
1243 return true;
1244 }
1245
ChooseStreamToPlay(MediaAVCodec::MediaType type)1246 bool DashMpdDownloader::ChooseStreamToPlay(MediaAVCodec::MediaType type)
1247 {
1248 if (mpdInfo_ == nullptr || streamDescriptions_.size() == 0) {
1249 return false;
1250 }
1251
1252 std::shared_ptr<DashStreamDescription> choosedStream = nullptr;
1253 std::shared_ptr<DashStreamDescription> backupStream = nullptr;
1254 for (const auto &stream : streamDescriptions_) {
1255 if (stream->type_ != type || stream->inUse_) {
1256 continue;
1257 }
1258
1259 if (type != MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1260 // audio and subtitle choose first stream to play or get default lang
1261 if (choosedStream == nullptr) {
1262 choosedStream = stream;
1263 }
1264 if (!IsLangMatch(stream->lang_, type)) {
1265 continue;
1266 }
1267
1268 choosedStream = stream;
1269 break;
1270 }
1271
1272 if (backupStream == nullptr || IsNearToInitResolution(backupStream, stream) ||
1273 (initResolution_ == 0 && backupStream->bandwidth_ > stream->bandwidth_)) {
1274 backupStream = stream;
1275 }
1276
1277 if ((stream->videoType_ != DASH_VIDEO_TYPE_SDR) != isHdrStart_) {
1278 continue;
1279 }
1280
1281 if (IsChoosedVideoStream(choosedStream, stream)) {
1282 choosedStream = stream;
1283 }
1284 }
1285
1286 if (choosedStream == nullptr && type == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1287 MEDIA_LOG_I("ChooseStreamToPlay video can not find hdrstart:" PUBLIC_LOG_D32, isHdrStart_);
1288 choosedStream = backupStream;
1289 }
1290
1291 if (choosedStream != nullptr) {
1292 choosedStream->inUse_ = true;
1293 MEDIA_LOG_I("ChooseStreamToPlay type:" PUBLIC_LOG_D32 ", streamId:"
1294 PUBLIC_LOG_D32, (int) type, choosedStream->streamId_);
1295 if (!ondemandSegBase_) {
1296 GetSegmentsInMpd(choosedStream);
1297 }
1298 return true;
1299 }
1300
1301 return false;
1302 }
1303
GetSegTimeBySeq(const std::vector<std::shared_ptr<DashSegment>> & segments,int64_t segSeq)1304 unsigned int DashMpdDownloader::GetSegTimeBySeq(const std::vector<std::shared_ptr<DashSegment>> &segments,
1305 int64_t segSeq)
1306 {
1307 if (segments.size() == 0) {
1308 return 0;
1309 }
1310
1311 unsigned int nextSegTime = 0;
1312 for (unsigned int index = 0; index < segments.size(); index++) {
1313 if (segments[index]->numberSeq_ > segSeq) {
1314 break;
1315 }
1316
1317 nextSegTime += segments[index]->duration_;
1318 }
1319
1320 return nextSegTime;
1321 }
1322
GetSegmentsInMpd(std::shared_ptr<DashStreamDescription> streamDesc)1323 DashSegmentInitValue DashMpdDownloader::GetSegmentsInMpd(std::shared_ptr<DashStreamDescription> streamDesc)
1324 {
1325 if (mpdInfo_ == nullptr || streamDesc == nullptr) {
1326 MEDIA_LOG_E("GetSegments but mpdInfo_ or streamDesc is nullptr");
1327 return DASH_SEGMENT_INIT_FAILED;
1328 }
1329
1330 streamDesc->segsState_ = DASH_SEGS_STATE_FINISH;
1331 std::string mpdBaseUrl;
1332 mpdManager_->SetMpdInfo(mpdInfo_, url_);
1333 mpdBaseUrl = mpdManager_->GetBaseUrl();
1334
1335 unsigned int currentPeriodIndex = 0;
1336 for (std::list<DashPeriodInfo *>::iterator it = mpdInfo_->periodInfoList_.begin();
1337 it != mpdInfo_->periodInfoList_.end(); ++it, ++currentPeriodIndex) {
1338 if (*it != nullptr && currentPeriodIndex == streamDesc->periodIndex_) {
1339 if (GetSegmentsInPeriod(*it, mpdBaseUrl, streamDesc) == DASH_SEGMENT_INIT_FAILED) {
1340 MEDIA_LOG_I("GetSegmentsInPeriod" PUBLIC_LOG_U32 " failed, type "
1341 PUBLIC_LOG_D32, currentPeriodIndex, streamDesc->type_);
1342 return DASH_SEGMENT_INIT_FAILED;
1343 }
1344
1345 break;
1346 }
1347 }
1348
1349 if (streamDesc->mediaSegments_.size() == 0) {
1350 MEDIA_LOG_E("GetSegmentsInMpd failed, type " PUBLIC_LOG_D32, streamDesc->type_);
1351 return DASH_SEGMENT_INIT_FAILED;
1352 }
1353
1354 std::shared_ptr<DashSegment> lastSegment = streamDesc->mediaSegments_[streamDesc->mediaSegments_.size() - 1];
1355 if (lastSegment != nullptr && mpdInfo_ != nullptr && mpdInfo_->type_ == DashType::DASH_TYPE_STATIC) {
1356 lastSegment->isLast_ = true;
1357 }
1358 return DASH_SEGMENT_INIT_SUCCESS;
1359 }
1360
GetSegmentsInPeriod(DashPeriodInfo * periodInfo,const std::string & mpdBaseUrl,std::shared_ptr<DashStreamDescription> streamDesc)1361 DashSegmentInitValue DashMpdDownloader::GetSegmentsInPeriod(DashPeriodInfo *periodInfo, const std::string &mpdBaseUrl,
1362 std::shared_ptr<DashStreamDescription> streamDesc)
1363 {
1364 std::vector<DashAdptSetInfo*> adptSetVector;
1365 DashSegmentInitValue initValue = DASH_SEGMENT_INIT_UNDO;
1366 std::string periodBaseUrl = mpdBaseUrl;
1367 periodManager_->SetPeriodInfo(periodInfo);
1368 periodManager_->GetAdptSetsByStreamType(adptSetVector, streamDesc->type_);
1369 DashAdptSetInfo *adptSetInfo = nullptr;
1370
1371 if (streamDesc->adptSetIndex_ < adptSetVector.size()) {
1372 adptSetInfo = adptSetVector[streamDesc->adptSetIndex_];
1373 DashAppendBaseUrl(periodBaseUrl, periodInfo->baseUrl_);
1374 initValue = GetSegmentsInAdptSet(adptSetInfo, periodBaseUrl, streamDesc);
1375 if (initValue != DASH_SEGMENT_INIT_UNDO) {
1376 return initValue;
1377 }
1378 }
1379
1380 // segments in period.segmentList/segmentTemplate/baseurl, should store in video stream manager
1381 if (streamDesc->type_ != MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1382 return initValue;
1383 }
1384
1385 // UST182 base to relative segment url
1386 periodBaseUrl = mpdBaseUrl;
1387 initValue = GetSegmentsByPeriodInfo(periodInfo, adptSetInfo, periodBaseUrl, streamDesc);
1388 if (initValue == DASH_SEGMENT_INIT_SUCCESS) {
1389 MakeAbsoluteWithBaseUrl(streamDesc->mediaSegments_, periodBaseUrl);
1390 }
1391
1392 return initValue;
1393 }
1394
GetSegmentsInAdptSet(DashAdptSetInfo * adptSetInfo,const std::string & periodBaseUrl,std::shared_ptr<DashStreamDescription> streamDesc)1395 DashSegmentInitValue DashMpdDownloader::GetSegmentsInAdptSet(DashAdptSetInfo *adptSetInfo,
1396 const std::string &periodBaseUrl,
1397 std::shared_ptr<DashStreamDescription> streamDesc)
1398 {
1399 if (adptSetInfo == nullptr) {
1400 return DASH_SEGMENT_INIT_UNDO;
1401 }
1402
1403 DashSegmentInitValue initValue = DASH_SEGMENT_INIT_UNDO;
1404 DashRepresentationInfo* repInfo = nullptr;
1405 std::string adptSetBaseUrl = periodBaseUrl;
1406
1407 if (streamDesc->representationIndex_ < adptSetInfo->representationList_.size()) {
1408 repInfo = GetRepresemtationFromAdptSet(adptSetInfo, streamDesc->representationIndex_);
1409 if (repInfo != nullptr) {
1410 DashAppendBaseUrl(adptSetBaseUrl, adptSetInfo->baseUrl_);
1411 initValue = GetSegmentsInRepresentation(repInfo, adptSetBaseUrl, streamDesc);
1412 }
1413
1414 if (initValue != DASH_SEGMENT_INIT_UNDO) {
1415 return initValue;
1416 }
1417 }
1418
1419 adptSetBaseUrl = periodBaseUrl;
1420 initValue = GetSegmentsByAdptSetInfo(adptSetInfo, repInfo, adptSetBaseUrl, streamDesc);
1421 if (initValue == DASH_SEGMENT_INIT_SUCCESS) {
1422 MakeAbsoluteWithBaseUrl(streamDesc->mediaSegments_, adptSetBaseUrl);
1423 }
1424
1425 return initValue;
1426 }
1427
GetSegmentsInRepresentation(DashRepresentationInfo * repInfo,const std::string & adptSetBaseUrl,std::shared_ptr<DashStreamDescription> streamDesc)1428 DashSegmentInitValue DashMpdDownloader::GetSegmentsInRepresentation(DashRepresentationInfo *repInfo,
1429 const std::string &adptSetBaseUrl,
1430 std::shared_ptr<DashStreamDescription> streamDesc)
1431 {
1432 std::string repBaseUrl = adptSetBaseUrl;
1433 DashSegmentInitValue initValue = DASH_SEGMENT_INIT_UNDO;
1434 if (repInfo->representationSegTmplt_ != nullptr && repInfo->representationSegTmplt_->segTmpltMedia_.length() > 0) {
1435 DashAppendBaseUrl(repBaseUrl, repInfo->baseUrl_);
1436 initValue = GetSegmentsWithSegTemplate(repInfo->representationSegTmplt_, repInfo->id_, streamDesc);
1437 } else if (repInfo->representationSegList_ != nullptr && repInfo->representationSegList_->segmentUrl_.size() > 0) {
1438 // get segments from Representation.SegmentList
1439 DashAppendBaseUrl(repBaseUrl, repInfo->baseUrl_);
1440 initValue = GetSegmentsWithSegList(repInfo->representationSegList_, repBaseUrl, streamDesc);
1441 } else if (repInfo->baseUrl_.size() > 0) {
1442 // get one segment from Representation.BaseUrl
1443 initValue = GetSegmentsWithBaseUrl(repInfo->baseUrl_, streamDesc);
1444 }
1445
1446 if (initValue == DASH_SEGMENT_INIT_SUCCESS) {
1447 MakeAbsoluteWithBaseUrl(streamDesc->mediaSegments_, repBaseUrl);
1448 }
1449
1450 return initValue;
1451 }
1452
GetSegmentsWithSegTemplate(const DashSegTmpltInfo * segTmpltInfo,std::string id,std::shared_ptr<DashStreamDescription> streamDesc)1453 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithSegTemplate(const DashSegTmpltInfo *segTmpltInfo, std::string id,
1454 std::shared_ptr<DashStreamDescription> streamDesc)
1455 {
1456 std::string media = segTmpltInfo->segTmpltMedia_;
1457 std::string::size_type posIden = media.find("$$");
1458 if (posIden != std::string::npos) {
1459 size_t strLength = strlen("$$");
1460 media.replace(posIden, strLength, "$");
1461 }
1462
1463 if (DashSubstituteTmpltStr(media, "$RepresentationID", id) == -1) {
1464 MEDIA_LOG_E("media " PUBLIC_LOG_S " substitute $RepresentationID error "
1465 PUBLIC_LOG_S, media.c_str(), id.c_str());
1466 return DASH_SEGMENT_INIT_FAILED;
1467 }
1468
1469 if (DashSubstituteTmpltStr(media, "$Bandwidth", std::to_string(streamDesc->bandwidth_)) == -1) {
1470 MEDIA_LOG_E("media " PUBLIC_LOG_S " substitute $Bandwidth error " PUBLIC_LOG_D32, media.c_str(),
1471 streamDesc->bandwidth_);
1472 return DASH_SEGMENT_INIT_FAILED;
1473 }
1474
1475 streamDesc->startNumberSeq_ = ParseStartNumber(segTmpltInfo->multSegBaseInfo_.startNumber_);
1476 if (mpdInfo_->type_ == DashType::DASH_TYPE_STATIC) {
1477 return GetSegmentsWithTmpltStatic(segTmpltInfo, media, streamDesc);
1478 }
1479
1480 return DASH_SEGMENT_INIT_FAILED;
1481 }
1482
GetSegmentsWithTmpltStatic(const DashSegTmpltInfo * segTmpltInfo,const std::string & mediaUrl,std::shared_ptr<DashStreamDescription> streamDesc)1483 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithTmpltStatic(const DashSegTmpltInfo *segTmpltInfo,
1484 const std::string &mediaUrl,
1485 std::shared_ptr<DashStreamDescription> streamDesc)
1486 {
1487 unsigned int timeScale = 1;
1488 if (segTmpltInfo->multSegBaseInfo_.segBaseInfo_.timeScale_ > 0) {
1489 timeScale = segTmpltInfo->multSegBaseInfo_.segBaseInfo_.timeScale_;
1490 }
1491
1492 if (segTmpltInfo->multSegBaseInfo_.duration_ > 0) {
1493 return GetSegmentsWithTmpltDurationStatic(segTmpltInfo, mediaUrl, timeScale, streamDesc);
1494 } else if (segTmpltInfo->multSegBaseInfo_.segTimeline_.size() > 0) {
1495 return GetSegmentsWithTmpltTimelineStatic(segTmpltInfo, mediaUrl, timeScale, streamDesc);
1496 } else {
1497 MEDIA_LOG_E("static SegmentTemplate do not have segment duration");
1498 return DASH_SEGMENT_INIT_FAILED;
1499 }
1500 }
1501
1502 /**
1503 * @brief Get segments with SegmentTemplate in static as contain SegmentBase.duration
1504 *
1505 * @param segTmpltInfo SegmentTemplate infomation
1506 * @param mediaUrl SegmentTemplate mediaSegment Url
1507 * @param timeScale the timeScale of this period, duration / timescale = seconds
1508 * @param desc stream description
1509 *
1510 * @return DashSegmentInitValue
1511 */
GetSegmentsWithTmpltDurationStatic(const DashSegTmpltInfo * segTmpltInfo,const std::string & mediaUrl,unsigned int timeScale,std::shared_ptr<DashStreamDescription> desc)1512 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithTmpltDurationStatic(const DashSegTmpltInfo *segTmpltInfo,
1513 const std::string &mediaUrl,
1514 unsigned int timeScale,
1515 std::shared_ptr<DashStreamDescription> desc)
1516 {
1517 unsigned int timeScaleTmp = timeScale > 0 ? timeScale : 1;
1518 // the segment duration in millisecond
1519 unsigned int segmentDuration =
1520 (static_cast<uint64_t>(segTmpltInfo->multSegBaseInfo_.duration_) * S_2_MS) / timeScaleTmp;
1521 if (segmentDuration == 0) {
1522 return DASH_SEGMENT_INIT_FAILED;
1523 }
1524
1525 uint64_t segmentBaseDurationSum = 0; // the sum of segment duration(ms), not devide timescale
1526 unsigned int accumulateDuration = 0; // add all segments dutation(ms) before current segment
1527 int64_t segmentSeq = -1;
1528
1529 while (accumulateDuration < desc->duration_) {
1530 segmentBaseDurationSum += segTmpltInfo->multSegBaseInfo_.duration_;
1531 // the sum of segment duration(ms), devide timescale
1532 unsigned int durationSumWithScale = static_cast<unsigned int>(segmentBaseDurationSum * S_2_MS / timeScaleTmp);
1533 unsigned int segRealDur = (durationSumWithScale > accumulateDuration) ?
1534 (durationSumWithScale - accumulateDuration) : segmentDuration;
1535
1536 if (desc->duration_ - accumulateDuration < segRealDur) {
1537 segRealDur = desc->duration_ - accumulateDuration;
1538 }
1539
1540 accumulateDuration += segRealDur;
1541 segmentSeq = (segmentSeq == -1) ? desc->startNumberSeq_ : (segmentSeq + 1);
1542
1543 // if the @duration attribute is present
1544 // then the time address is determined by replacing the $Time$ identifier with ((k-1) + (kStart-1))* @duration
1545 // with kStart the value of the @startNumber attribute, if present, or 1 otherwise.
1546 int64_t startTime = (segmentSeq - 1) * segTmpltInfo->multSegBaseInfo_.duration_;
1547 std::string tempUrl = mediaUrl;
1548
1549 if (DashSubstituteTmpltStr(tempUrl, "$Time", std::to_string(startTime)) == -1) {
1550 MEDIA_LOG_I("GetSegmentsWithTmpltDuration substitute $Time " PUBLIC_LOG_S " error in static duration",
1551 std::to_string(startTime).c_str());
1552 return DASH_SEGMENT_INIT_FAILED;
1553 }
1554
1555 if (DashSubstituteTmpltStr(tempUrl, "$Number", std::to_string(segmentSeq)) == -1) {
1556 MEDIA_LOG_I("GetSegmentsWithTmpltDuration substitute $Number " PUBLIC_LOG_S " error in static duration",
1557 std::to_string(segmentSeq).c_str());
1558 return DASH_SEGMENT_INIT_FAILED;
1559 }
1560
1561 if (DASH_SEGMENT_INIT_FAILED == AddOneSegment(segRealDur, segmentSeq, tempUrl, desc)) {
1562 return DASH_SEGMENT_INIT_FAILED;
1563 }
1564 }
1565 return DASH_SEGMENT_INIT_SUCCESS;
1566 }
1567
GetSegmentsWithTmpltTimelineStatic(const DashSegTmpltInfo * segTmpltInfo,const std::string & mediaUrl,unsigned int timeScale,std::shared_ptr<DashStreamDescription> desc)1568 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithTmpltTimelineStatic(const DashSegTmpltInfo *segTmpltInfo,
1569 const std::string &mediaUrl,
1570 unsigned int timeScale,
1571 std::shared_ptr<DashStreamDescription> desc)
1572 {
1573 if (timeScale == 0) {
1574 return DASH_SEGMENT_INIT_FAILED;
1575 }
1576
1577 int64_t segmentSeq = -1;
1578 uint64_t startTime = 0;
1579 std::list<DashSegTimeline*> timelineList = segTmpltInfo->multSegBaseInfo_.segTimeline_;
1580 for (std::list<DashSegTimeline*>::iterator it = timelineList.begin(); it != timelineList.end(); ++it) {
1581 if (*it != nullptr) {
1582 int segCount = GetSegCountFromTimeline(it, timelineList.end(), desc->duration_, timeScale, startTime);
1583 if (segCount < 0) {
1584 MEDIA_LOG_W("get segment count error in SegmentTemplate.SegmentTimeline");
1585 continue;
1586 }
1587
1588 unsigned int segDuration = ((*it)->d_ * S_2_MS) / timeScale;
1589 MediaSegSampleInfo sampleInfo;
1590 sampleInfo.mediaUrl_ = mediaUrl;
1591 sampleInfo.segCount_ = segCount;
1592 sampleInfo.segDuration_ = segDuration;
1593 if (GetSegmentsInOneTimeline(*it, sampleInfo, segmentSeq, startTime, desc) ==
1594 DASH_SEGMENT_INIT_FAILED) {
1595 return DASH_SEGMENT_INIT_FAILED;
1596 }
1597 }
1598 }
1599
1600 return DASH_SEGMENT_INIT_SUCCESS;
1601 }
1602
1603 /**
1604 * @brief Get segments in ome timeline
1605 *
1606 * @param timeline Segment Timeline infomation
1607 * @param sampleInfo segment count duration Url in timeline
1608 * @param segmentSeq[out] segment segquence in timeline
1609 * @param startTime[out] segment start time in timeline
1610 * @param streamDesc[out] stream description, segments store in it
1611 *
1612 * @return 0 indicates success, -1 indicates failed
1613 */
GetSegmentsInOneTimeline(const DashSegTimeline * timeline,const MediaSegSampleInfo & sampleInfo,int64_t & segmentSeq,uint64_t & startTime,std::shared_ptr<DashStreamDescription> streamDesc)1614 DashSegmentInitValue DashMpdDownloader::GetSegmentsInOneTimeline(const DashSegTimeline *timeline,
1615 const MediaSegSampleInfo &sampleInfo,
1616 int64_t &segmentSeq, uint64_t &startTime,
1617 std::shared_ptr<DashStreamDescription> streamDesc)
1618 {
1619 int repeat = 0;
1620 int segCountTmp = sampleInfo.segCount_;
1621
1622 while (repeat <= segCountTmp) {
1623 repeat++;
1624 if (segmentSeq == -1) {
1625 segmentSeq = streamDesc->startNumberSeq_;
1626 } else {
1627 segmentSeq++;
1628 }
1629
1630 std::string tempUrl = sampleInfo.mediaUrl_;
1631 if (DashSubstituteTmpltStr(tempUrl, "$Time", std::to_string(startTime)) == -1) {
1632 MEDIA_LOG_E("GetSegmentsInOneTimeline substitute $Time " PUBLIC_LOG_S " error in static timeline",
1633 std::to_string(startTime).c_str());
1634 return DASH_SEGMENT_INIT_FAILED;
1635 }
1636
1637 if (DashSubstituteTmpltStr(tempUrl, "$Number", std::to_string(segmentSeq)) == -1) {
1638 MEDIA_LOG_E("GetSegmentsInOneTimeline substitute $Number " PUBLIC_LOG_S " error in static timeline",
1639 std::to_string(segmentSeq).c_str());
1640 return DASH_SEGMENT_INIT_FAILED;
1641 }
1642
1643 if (DASH_SEGMENT_INIT_FAILED == AddOneSegment(sampleInfo.segDuration_, segmentSeq, tempUrl, streamDesc)) {
1644 MEDIA_LOG_E("AddOneSegment with SegmentTimeline in static is failed");
1645 return DASH_SEGMENT_INIT_FAILED;
1646 }
1647
1648 startTime += timeline->d_;
1649 }
1650
1651 return DASH_SEGMENT_INIT_SUCCESS;
1652 }
1653
1654 /**
1655 * @brief Get Segment Repeat Count In SegmentTimeline.S
1656 *
1657 * @param it the current S element infomation iterator of list
1658 * @param end the end iterator of list
1659 * @param periodDuration the duration of this period
1660 * @param timeScale the timeScale of this period, duration / timescale = seconds
1661 * @param startTime segment start time in timeline
1662 *
1663 * @return segment repeat count, 0 means only one segment, negative means no segment
1664 */
GetSegCountFromTimeline(DashList<DashSegTimeline * >::iterator & it,const DashList<DashSegTimeline * >::iterator & end,unsigned int periodDuration,unsigned int timeScale,uint64_t startTime)1665 int DashMpdDownloader::GetSegCountFromTimeline(DashList<DashSegTimeline *>::iterator &it,
1666 const DashList<DashSegTimeline *>::iterator &end,
1667 unsigned int periodDuration, unsigned int timeScale, uint64_t startTime)
1668 {
1669 int segCount = (*it)->r_;
1670
1671 /* A negative value of the @r attribute of the S element indicates that
1672 * the duration indicated in @d attribute repeats until the start of
1673 * the next S element, the end of the Period or until the next MPD update.
1674 */
1675 if (segCount < 0 && (*it)->d_) {
1676 ++it;
1677 // the start of next S
1678 if (it != end && *it != nullptr) {
1679 uint64_t nextStartTime = (*it)->t_;
1680 it--;
1681
1682 if (nextStartTime <= startTime) {
1683 MEDIA_LOG_W("r is negative and next S@t " PUBLIC_LOG_U64 " is not larger than startTime "
1684 PUBLIC_LOG_U64, nextStartTime, startTime);
1685 return segCount;
1686 }
1687
1688 segCount = (int)((nextStartTime - startTime) / (*it)->d_);
1689 } else {
1690 // the end of period
1691 it--;
1692 uint64_t scaleDuration = (uint64_t)periodDuration * timeScale / S_2_MS;
1693 if (scaleDuration <= startTime) {
1694 MEDIA_LOG_W("r is negative, duration " PUBLIC_LOG_U32 " is not larger than startTime "
1695 PUBLIC_LOG_U64 ", timeScale " PUBLIC_LOG_U32, periodDuration, startTime, timeScale);
1696 return segCount;
1697 }
1698
1699 segCount = (int)((scaleDuration - startTime) / (*it)->d_);
1700 }
1701
1702 // 0 means only one segment
1703 segCount -= 1;
1704 }
1705
1706 return segCount;
1707 }
1708
1709 /**
1710 * @brief get segments with SegmentList
1711 *
1712 * @param segListInfo SegmentList infomation
1713 * @param baseUrl BaseUrl that map to media attribute if media missed and range present
1714 * @param streamDesc stream description, store segments
1715 *
1716 * @return failed success undo
1717 */
GetSegmentsWithSegList(const DashSegListInfo * segListInfo,const std::string & baseUrl,std::shared_ptr<DashStreamDescription> streamDesc)1718 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithSegList(const DashSegListInfo *segListInfo,
1719 const std::string &baseUrl,
1720 std::shared_ptr<DashStreamDescription> streamDesc)
1721 {
1722 int64_t segmentSeq = -1;
1723 int segmentCount = 0;
1724 std::list<unsigned int> durationList;
1725
1726 unsigned int timescale = 1;
1727 if (segListInfo->multSegBaseInfo_.segBaseInfo_.timeScale_ != 0) {
1728 timescale = segListInfo->multSegBaseInfo_.segBaseInfo_.timeScale_;
1729 }
1730
1731 unsigned int segDuration = (static_cast<uint64_t>(segListInfo->multSegBaseInfo_.duration_) * S_2_MS) / timescale;
1732 GetSegDurationFromTimeline(streamDesc->duration_, timescale, &segListInfo->multSegBaseInfo_, durationList);
1733
1734 std::list<DashSegUrl*> segUrlList = segListInfo->segmentUrl_;
1735 for (std::list<DashSegUrl*>::iterator it = segUrlList.begin(); it != segUrlList.end(); ++it) {
1736 if (*it == nullptr) {
1737 continue;
1738 }
1739
1740 std::string mediaUrl;
1741 if ((*it)->media_.length() > 0) {
1742 mediaUrl = (*it)->media_;
1743 } else if (baseUrl.length() > 0) {
1744 mediaUrl = ""; // append baseurl as the media url in MakeAbsoluteWithBaseUrl
1745 } else {
1746 continue;
1747 }
1748 segmentSeq = streamDesc->startNumberSeq_ + segmentCount;
1749 DashSegment srcSegment;
1750 srcSegment.streamId_ = streamDesc->streamId_;
1751 srcSegment.bandwidth_ = streamDesc->bandwidth_;
1752 if (durationList.size() > 0) {
1753 // by SegmentTimeline
1754 srcSegment.duration_ = durationList.front();
1755 // if size of SegmentTimeline smaller than size of SegmentURL,
1756 // keep the last segment duration in SegmentTimeline
1757 if (durationList.size() > 1) {
1758 durationList.pop_front();
1759 }
1760 } else {
1761 // by duration
1762 srcSegment.duration_ = segDuration;
1763 }
1764
1765 srcSegment.startNumberSeq_ = streamDesc->startNumberSeq_;
1766 srcSegment.numberSeq_ = segmentSeq;
1767 srcSegment.url_ = mediaUrl;
1768 srcSegment.byteRange_ = (*it)->mediaRange_;
1769 if (DASH_SEGMENT_INIT_FAILED == AddOneSegment(srcSegment, streamDesc)) {
1770 return DASH_SEGMENT_INIT_FAILED;
1771 }
1772 segmentCount++;
1773 }
1774
1775 return DASH_SEGMENT_INIT_SUCCESS;
1776 }
1777
1778 /**
1779 * @brief Get Segment Duration From SegmentTimeline
1780 *
1781 * @param periodDuration the duration of this period
1782 * @param timeScale the timeScale of this period, duration / timescale = seconds
1783 * @param multSegBaseInfo multipleSegmentBaseInfomation in segmentlist
1784 * @param durationList[out] the list to store segment duration
1785 *
1786 * @return none
1787 */
GetSegDurationFromTimeline(unsigned int periodDuration,unsigned int timeScale,const DashMultSegBaseInfo * multSegBaseInfo,DashList<unsigned int> & durationList)1788 void DashMpdDownloader::GetSegDurationFromTimeline(unsigned int periodDuration, unsigned int timeScale,
1789 const DashMultSegBaseInfo *multSegBaseInfo,
1790 DashList<unsigned int> &durationList)
1791 {
1792 if (timeScale == 0 || mpdInfo_ == nullptr) {
1793 return;
1794 }
1795
1796 // support SegmentList.SegmentTimeline in static type
1797 if (multSegBaseInfo->duration_ == 0 && multSegBaseInfo->segTimeline_.size() > 0 &&
1798 mpdInfo_->type_ == DashType::DASH_TYPE_STATIC) {
1799 uint64_t startTime = 0;
1800 std::list<DashSegTimeline*> timelineList = multSegBaseInfo->segTimeline_;
1801 for (std::list<DashSegTimeline*>::iterator it = timelineList.begin(); it != timelineList.end(); ++it) {
1802 if (*it == nullptr) {
1803 continue;
1804 }
1805 int segCount = GetSegCountFromTimeline(it, timelineList.end(), periodDuration, timeScale, startTime);
1806 if (segCount < 0) {
1807 MEDIA_LOG_W("get segment count error in SegmentList.SegmentTimeline");
1808 continue;
1809 }
1810 // calculate segment duration by SegmentTimeline
1811 unsigned int segDuration = ((*it)->d_ * 1000) / timeScale;
1812 for (int repeat = 0; repeat <= segCount; repeat++) {
1813 durationList.push_back(segDuration);
1814 startTime += (*it)->d_;
1815 }
1816 }
1817 }
1818 }
1819
1820 /**
1821 * @brief init segments with BaseUrl
1822 *
1823 * @param baseUrlList BaseUrl List
1824 * @param streamDesc stream description, store segments
1825 * @return failed success undo
1826 */
GetSegmentsWithBaseUrl(std::list<std::string> baseUrlList,std::shared_ptr<DashStreamDescription> streamDesc)1827 DashSegmentInitValue DashMpdDownloader::GetSegmentsWithBaseUrl(std::list<std::string> baseUrlList,
1828 std::shared_ptr<DashStreamDescription> streamDesc)
1829 {
1830 DashSegment srcSegment;
1831 srcSegment.streamId_ = streamDesc->streamId_;
1832 srcSegment.bandwidth_ = streamDesc->bandwidth_;
1833 srcSegment.duration_ = streamDesc->duration_;
1834 srcSegment.startNumberSeq_ = streamDesc->startNumberSeq_;
1835 srcSegment.numberSeq_ = streamDesc->startNumberSeq_;
1836 if (baseUrlList.size() > 0) {
1837 srcSegment.url_ = baseUrlList.front();
1838 }
1839
1840 if (DASH_SEGMENT_INIT_FAILED == AddOneSegment(srcSegment, streamDesc)) {
1841 MEDIA_LOG_E("GetSegmentsWithBaseUrl AddOneSegment is failed");
1842 return DASH_SEGMENT_INIT_FAILED;
1843 }
1844
1845 return DASH_SEGMENT_INIT_SUCCESS;
1846 }
1847
GetRepresemtationFromAdptSet(DashAdptSetInfo * adptSetInfo,unsigned int repIndex)1848 DashRepresentationInfo *DashMpdDownloader::GetRepresemtationFromAdptSet(DashAdptSetInfo *adptSetInfo,
1849 unsigned int repIndex)
1850 {
1851 unsigned int index = 0;
1852 for (std::list<DashRepresentationInfo *>::iterator it = adptSetInfo->representationList_.begin();
1853 it != adptSetInfo->representationList_.end(); ++it, ++index) {
1854 if (repIndex == index) {
1855 return *it;
1856 }
1857 }
1858
1859 return nullptr;
1860 }
1861
1862 /**
1863 * @brief get segments in AdaptationSet with SegmentTemplate or SegmentList or BaseUrl
1864 *
1865 * @param adptSetInfo chosen AdaptationSet
1866 * @param repInfo use its id as get segments with SegmentTemplate
1867 * @param baseUrl Mpd.BaseUrl + Period.BaseUrl
1868 * @param streamDesc stream description, store segments
1869 *
1870 * @return failed success undo
1871 */
GetSegmentsByAdptSetInfo(const DashAdptSetInfo * adptSetInfo,const DashRepresentationInfo * repInfo,std::string & baseUrl,std::shared_ptr<DashStreamDescription> streamDesc)1872 DashSegmentInitValue DashMpdDownloader::GetSegmentsByAdptSetInfo(const DashAdptSetInfo* adptSetInfo,
1873 const DashRepresentationInfo* repInfo, std::string& baseUrl, std::shared_ptr<DashStreamDescription> streamDesc)
1874 {
1875 DashSegmentInitValue initValue = DASH_SEGMENT_INIT_UNDO;
1876
1877 // get segments from AdaptationSet.SegmentTemplate
1878 if (adptSetInfo->adptSetSegTmplt_ != nullptr && adptSetInfo->adptSetSegTmplt_->segTmpltMedia_.length() > 0) {
1879 DashAppendBaseUrl(baseUrl, adptSetInfo->baseUrl_);
1880
1881 std::string representationId;
1882 if (repInfo != nullptr) {
1883 representationId = repInfo->id_;
1884 }
1885
1886 initValue = GetSegmentsWithSegTemplate(adptSetInfo->adptSetSegTmplt_, representationId, streamDesc);
1887 } else if (adptSetInfo->adptSetSegList_ != nullptr && adptSetInfo->adptSetSegList_->segmentUrl_.size() > 0) {
1888 // get segments from AdaptationSet.SegmentList
1889 DashAppendBaseUrl(baseUrl, adptSetInfo->baseUrl_);
1890 initValue = GetSegmentsWithSegList(adptSetInfo->adptSetSegList_, baseUrl, streamDesc);
1891 } else if (adptSetInfo->baseUrl_.size() > 0) {
1892 initValue = GetSegmentsWithBaseUrl(adptSetInfo->baseUrl_, streamDesc);
1893 }
1894
1895 return initValue;
1896 }
1897
GetInitSegFromPeriod(const std::string & periodBaseUrl,const std::string & repId,std::shared_ptr<DashStreamDescription> streamDesc)1898 bool DashMpdDownloader::GetInitSegFromPeriod(const std::string &periodBaseUrl, const std::string &repId,
1899 std::shared_ptr<DashStreamDescription> streamDesc)
1900 {
1901 int segTmpltFlag = 0;
1902 // should SetPeriodInfo before GetInitSegment
1903 DashUrlType *initSegment = periodManager_->GetInitSegment(segTmpltFlag);
1904 if (initSegment != nullptr) {
1905 streamDesc->initSegment_ = std::make_shared<DashInitSegment>();
1906 UpdateInitSegUrl(streamDesc, initSegment, segTmpltFlag, repId);
1907 MakeAbsoluteWithBaseUrl(streamDesc->initSegment_, periodBaseUrl);
1908 MEDIA_LOG_D("GetInitSegFromPeriod:streamId:" PUBLIC_LOG_D32, streamDesc->streamId_);
1909 return true;
1910 }
1911
1912 return false;
1913 }
1914
GetInitSegFromAdptSet(const std::string & adptSetBaseUrl,const std::string & repId,std::shared_ptr<DashStreamDescription> streamDesc)1915 bool DashMpdDownloader::GetInitSegFromAdptSet(const std::string &adptSetBaseUrl, const std::string &repId,
1916 std::shared_ptr<DashStreamDescription> streamDesc)
1917 {
1918 int segTmpltFlag = 0;
1919 // should SetAdptSetInfo before GetInitSegment
1920 DashUrlType *initSegment = adptSetManager_->GetInitSegment(segTmpltFlag);
1921 if (initSegment != nullptr) {
1922 streamDesc->initSegment_ = std::make_shared<DashInitSegment>();
1923 UpdateInitSegUrl(streamDesc, initSegment, segTmpltFlag, repId);
1924 MakeAbsoluteWithBaseUrl(streamDesc->initSegment_, adptSetBaseUrl);
1925 MEDIA_LOG_D("GetInitSegFromAdptSet:streamId:" PUBLIC_LOG_D32, streamDesc->streamId_);
1926 return true;
1927 }
1928
1929 return false;
1930 }
1931
GetInitSegFromRepresentation(const std::string & repBaseUrl,const std::string & repId,std::shared_ptr<DashStreamDescription> streamDesc)1932 bool DashMpdDownloader::GetInitSegFromRepresentation(const std::string &repBaseUrl, const std::string &repId,
1933 std::shared_ptr<DashStreamDescription> streamDesc)
1934 {
1935 int segTmpltFlag = 0;
1936 DashUrlType *initSegment = representationManager_->GetInitSegment(segTmpltFlag);
1937 // should SetRepresentationInfo before GetInitSegment
1938 if (initSegment != nullptr) {
1939 streamDesc->initSegment_ = std::make_shared<DashInitSegment>();
1940 UpdateInitSegUrl(streamDesc, initSegment, segTmpltFlag, repId);
1941 MakeAbsoluteWithBaseUrl(streamDesc->initSegment_, repBaseUrl);
1942 MEDIA_LOG_D("GetInitSegFromRepresentation:streamId:" PUBLIC_LOG_D32, streamDesc->streamId_);
1943 return true;
1944 }
1945
1946 return false;
1947 }
1948
GetSegmentsInNewStream(std::shared_ptr<DashStreamDescription> destStream)1949 DashMpdGetRet DashMpdDownloader::GetSegmentsInNewStream(std::shared_ptr<DashStreamDescription> destStream)
1950 {
1951 MEDIA_LOG_I("GetSegmentsInNewStream update id:" PUBLIC_LOG_D32 ", seq:"
1952 PUBLIC_LOG_D64, destStream->streamId_, destStream->currentNumberSeq_);
1953 DashMpdGetRet ret = DASH_MPD_GET_ERROR;
1954 if (destStream->segsState_ == DASH_SEGS_STATE_FINISH) {
1955 // segment list is ok
1956 MEDIA_LOG_I("GetNextVideoStream id:" PUBLIC_LOG_D32 ", segment list is ok", destStream->streamId_);
1957 ret = DASH_MPD_GET_DONE;
1958 } else {
1959 // get segment list
1960 if (ondemandSegBase_) {
1961 // request sidx segment
1962 if (destStream->indexSegment_ != nullptr) {
1963 ret = DASH_MPD_GET_UNDONE;
1964 OpenStream(destStream);
1965 } else {
1966 MEDIA_LOG_E("GetNextSegmentByBitrate id:"
1967 PUBLIC_LOG_D32 " ondemandSegBase_ but indexSegment is null", destStream->streamId_);
1968 }
1969 } else {
1970 // get segment list
1971 if (GetSegmentsInMpd(destStream) == DASH_SEGMENT_INIT_FAILED) {
1972 MEDIA_LOG_E("GetNextSegmentByBitrate id:"
1973 PUBLIC_LOG_D32 " GetSegmentsInMpd failed", destStream->streamId_);
1974 }
1975 // get segment by position
1976 ret = DASH_MPD_GET_DONE;
1977 }
1978 }
1979 return ret;
1980 }
1981
UpdateInitSegUrl(std::shared_ptr<DashStreamDescription> streamDesc,const DashUrlType * urlType,int segTmpltFlag,std::string representationID)1982 void DashMpdDownloader::UpdateInitSegUrl(std::shared_ptr<DashStreamDescription> streamDesc, const DashUrlType *urlType,
1983 int segTmpltFlag, std::string representationID)
1984 {
1985 if (streamDesc != nullptr && streamDesc->initSegment_ != nullptr) {
1986 streamDesc->initSegment_->url_ = urlType->sourceUrl_;
1987 if (urlType->range_.length() > 0) {
1988 DashParseRange(urlType->range_, streamDesc->initSegment_->rangeBegin_, streamDesc->initSegment_->rangeEnd_);
1989 }
1990
1991 if (segTmpltFlag) {
1992 std::string::size_type posIden = streamDesc->initSegment_->url_.find("$$");
1993 if (posIden != std::string::npos) {
1994 size_t strLength = strlen("$$");
1995 streamDesc->initSegment_->url_.replace(posIden, strLength, "$");
1996 }
1997
1998 if (DashSubstituteTmpltStr(streamDesc->initSegment_->url_, "$RepresentationID", representationID) == -1) {
1999 MEDIA_LOG_E("UpdateInitSegUrl subtitute $RepresentationID error "
2000 PUBLIC_LOG_S, representationID.c_str());
2001 }
2002
2003 if (DashSubstituteTmpltStr(streamDesc->initSegment_->url_, "$Bandwidth",
2004 std::to_string(streamDesc->bandwidth_)) == -1) {
2005 MEDIA_LOG_E("UpdateInitSegUrl subtitute $Bandwidth error "
2006 PUBLIC_LOG_U32, streamDesc->bandwidth_);
2007 }
2008 }
2009 }
2010 }
2011
GetVideoType(DashVideoType videoType)2012 static VideoType GetVideoType(DashVideoType videoType)
2013 {
2014 if (videoType == DASH_VIDEO_TYPE_HDR_VIVID) {
2015 return VIDEO_TYPE_HDR_VIVID;
2016 } else if (videoType == DASH_VIDEO_TYPE_HDR_10) {
2017 return VIDEO_TYPE_HDR_10;
2018 } else {
2019 return VIDEO_TYPE_SDR;
2020 }
2021 }
2022
GetStreamInfo(std::vector<StreamInfo> & streams)2023 Status DashMpdDownloader::GetStreamInfo(std::vector<StreamInfo> &streams)
2024 {
2025 MEDIA_LOG_I("GetStreamInfo");
2026 // only support one audio/subtitle Representation in one AdaptationSet
2027 unsigned int audioAdptSetIndex = streamDescriptions_.size();
2028 unsigned int subtitleAdptSetIndex = audioAdptSetIndex;
2029 for (unsigned int index = 0; index < streamDescriptions_.size(); index++) {
2030 if (streamDescriptions_[index]->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_AUD) {
2031 if (streamDescriptions_[index]->adptSetIndex_ == audioAdptSetIndex) {
2032 MEDIA_LOG_D("GetStreamInfo skip audio stream:" PUBLIC_LOG_D32 ",lang:" PUBLIC_LOG_S,
2033 streamDescriptions_[index]->streamId_, streamDescriptions_[index]->lang_.c_str());
2034 continue;
2035 }
2036
2037 audioAdptSetIndex = streamDescriptions_[index]->adptSetIndex_;
2038 } else if (streamDescriptions_[index]->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
2039 if (streamDescriptions_[index]->adptSetIndex_ == subtitleAdptSetIndex) {
2040 MEDIA_LOG_D("GetStreamInfo skip subtitle stream:" PUBLIC_LOG_D32 ",lang:" PUBLIC_LOG_S,
2041 streamDescriptions_[index]->streamId_, streamDescriptions_[index]->lang_.c_str());
2042 continue;
2043 }
2044 subtitleAdptSetIndex = streamDescriptions_[index]->adptSetIndex_;
2045 }
2046
2047 StreamInfo info;
2048 info.streamId = streamDescriptions_[index]->streamId_;
2049 info.bitRate = streamDescriptions_[index]->bandwidth_;
2050 info.videoWidth = static_cast<int32_t>(streamDescriptions_[index]->width_);
2051 info.videoHeight = static_cast<int32_t>(streamDescriptions_[index]->height_);
2052 info.lang = streamDescriptions_[index]->lang_;
2053 info.videoType = GetVideoType(streamDescriptions_[index]->videoType_);
2054 if (streamDescriptions_[index]->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
2055 info.type = SUBTITLE;
2056 } else if (streamDescriptions_[index]->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_AUD) {
2057 info.type = AUDIO;
2058 } else {
2059 info.type = VIDEO;
2060 }
2061
2062 MEDIA_LOG_D("GetStreamInfo streamId:" PUBLIC_LOG_D32 ", type:" PUBLIC_LOG_D32 ", bitRate:"
2063 PUBLIC_LOG_U32, info.streamId, info.type, info.bitRate);
2064 if (streamDescriptions_[index]->inUse_ && streams.size() > 0) {
2065 // play stream insert begin
2066 streams.insert(streams.begin(), info);
2067 } else {
2068 streams.push_back(info);
2069 }
2070 }
2071 return Status::OK;
2072 }
2073
PutStreamToDownload()2074 bool DashMpdDownloader::PutStreamToDownload()
2075 {
2076 auto iter = std::find_if(streamDescriptions_.begin(), streamDescriptions_.end(),
2077 [&](const std::shared_ptr<DashStreamDescription> &stream) {
2078 return stream->inUse_ &&
2079 stream->indexSegment_ != nullptr &&
2080 stream->segsState_ != DASH_SEGS_STATE_FINISH;
2081 });
2082 if (iter == streamDescriptions_.end()) {
2083 return false;
2084 }
2085
2086 OpenStream(*iter);
2087 return true;
2088 }
2089
2090 }
2091 }
2092 }
2093 }