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