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