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