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