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