• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2024 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 "DashMediaDownloader"
16 
17 #include <algorithm>
18 #include "dash_media_downloader.h"
19 #include "securec.h"
20 #include "plugin/plugin_time.h"
21 #include "osal/task/task.h"
22 #include "utils/time_utils.h"
23 #include "utils/bitrate_process_utils.h"
24 #include "format.h"
25 
26 namespace OHOS {
27 namespace Media {
28 namespace Plugins {
29 namespace HttpPlugin {
30 
31 constexpr double BUFFER_LOW_LIMIT  = 0.3;
32 constexpr double BYTE_TO_BIT = 8.0;
33 constexpr size_t RETRY_TIMES = 15000;
34 constexpr unsigned int SLEEP_TIME = 1;
35 constexpr uint32_t AUDIO_BUFFERING_FLAG = 1;
36 constexpr uint32_t VIDEO_BUFFERING_FLAG = 2;
37 
DashMediaDownloader(std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)38 DashMediaDownloader::DashMediaDownloader(std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)
39 {
40     if (sourceLoader != nullptr) {
41         MEDIA_LOG_I("DashMediaDownloader app download.");
42         sourceLoader_ = sourceLoader;
43     }
44     mpdDownloader_ = std::make_shared<DashMpdDownloader>(sourceLoader);
45     mpdDownloader_->SetMpdCallback(this);
46 }
47 
~DashMediaDownloader()48 DashMediaDownloader::~DashMediaDownloader()
49 {
50     if (mpdDownloader_ != nullptr) {
51         mpdDownloader_->Close(false);
52     }
53 
54     segmentDownloaders_.clear();
55 }
56 
Open(const std::string & url,const std::map<std::string,std::string> & httpHeader)57 bool DashMediaDownloader::Open(const std::string& url, const std::map<std::string, std::string>& httpHeader)
58 {
59     mpdDownloader_->Open(url);
60     return true;
61 }
62 
GetContentType()63 std::string DashMediaDownloader::GetContentType()
64 {
65     FALSE_RETURN_V(mpdDownloader_ != nullptr, "");
66     MEDIA_LOG_I("In");
67     return mpdDownloader_->GetContentType();
68 }
69 
Close(bool isAsync)70 void DashMediaDownloader::Close(bool isAsync)
71 {
72     mpdDownloader_->Close(isAsync);
73     for (unsigned int index = 0; index < segmentDownloaders_.size(); index++) {
74         segmentDownloaders_[index]->Close(isAsync, true);
75     }
76 }
77 
Pause()78 void DashMediaDownloader::Pause()
79 {
80     for (unsigned int index = 0; index < segmentDownloaders_.size(); index++) {
81         segmentDownloaders_[index]->Pause();
82     }
83 }
84 
Resume()85 void DashMediaDownloader::Resume()
86 {
87     for (unsigned int index = 0; index < segmentDownloaders_.size(); index++) {
88         segmentDownloaders_[index]->Resume();
89     }
90 }
91 
Read(unsigned char * buff,ReadDataInfo & readDataInfo)92 Status DashMediaDownloader::Read(unsigned char* buff, ReadDataInfo& readDataInfo)
93 {
94     FALSE_RETURN_V(buff != nullptr, Status::END_OF_STREAM);
95     if (segmentDownloaders_.empty()) {
96         MEDIA_LOG_W("dash read, segmentDownloaders size is 0");
97         return Status::END_OF_STREAM;
98     }
99 
100     if (downloadErrorState_) {
101         if (callback_ != nullptr) {
102             MEDIA_LOG_I("Read Client Error, OnEvent");
103             callback_->OnEvent({PluginEventType::CLIENT_ERROR, {NetworkClientErrorCode::ERROR_TIME_OUT}, "read"});
104         }
105         for (auto &segmentDownloader : segmentDownloaders_) {
106             segmentDownloader->Close(false, true);
107         }
108         return Status::ERROR_AGAIN;
109     }
110 
111     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloader(readDataInfo.streamId_);
112     if (segmentDownloader == nullptr) {
113         MEDIA_LOG_E("GetSegmentDownloader failed when Read, streamId " PUBLIC_LOG_D32, readDataInfo.streamId_);
114         return Status::END_OF_STREAM;
115     }
116 
117     DashReadRet ret = segmentDownloader->Read(buff, readDataInfo, isInterruptNeeded_);
118     MEDIA_LOG_D("Read:streamId " PUBLIC_LOG_D32 " readRet:" PUBLIC_LOG_D32, readDataInfo.streamId_, ret);
119     if (ret == DASH_READ_END) {
120         MEDIA_LOG_I("Read:streamId " PUBLIC_LOG_D32 " segment all finished end", readDataInfo.streamId_);
121         readDataInfo.isEos_ = true;
122         return Status::END_OF_STREAM;
123     } else if (ret == DASH_READ_AGAIN) {
124         return Status::ERROR_AGAIN;
125     } else if (ret == DASH_READ_FAILED || ret == DASH_READ_INTERRUPT) {
126         return Status::END_OF_STREAM;
127     }
128     return Status::OK;
129 }
130 
GetSegmentDownloader(int32_t streamId)131 std::shared_ptr<DashSegmentDownloader> DashMediaDownloader::GetSegmentDownloader(int32_t streamId)
132 {
133     std::shared_ptr<DashSegmentDownloader> segmentDownloader = nullptr;
134     std::shared_ptr<DashStreamDescription> streamDescription = mpdDownloader_->GetStreamByStreamId(streamId);
135     if (streamDescription == nullptr) {
136         MEDIA_LOG_E("stream " PUBLIC_LOG_D32 " not exist", streamId);
137         return segmentDownloader;
138     }
139     return GetSegmentDownloaderByType(streamDescription->type_);
140 }
141 
GetSegmentDownloaderByType(MediaAVCodec::MediaType type) const142 std::shared_ptr<DashSegmentDownloader> DashMediaDownloader::GetSegmentDownloaderByType(
143     MediaAVCodec::MediaType type) const
144 {
145     std::shared_ptr<DashSegmentDownloader> segmentDownloader = nullptr;
146     auto iter = std::find_if(segmentDownloaders_.begin(), segmentDownloaders_.end(),
147         [&](const std::shared_ptr<DashSegmentDownloader> &downloader) {
148             return downloader->GetStreamType() == type;
149         });
150     if (iter != segmentDownloaders_.end()) {
151         segmentDownloader = *iter;
152     }
153 
154     return segmentDownloader;
155 }
156 
UpdateDownloadFinished(int streamId)157 void DashMediaDownloader::UpdateDownloadFinished(int streamId)
158 {
159     MEDIA_LOG_I("UpdateDownloadFinished: " PUBLIC_LOG_D32, streamId);
160     std::shared_ptr<DashStreamDescription> streamDesc = mpdDownloader_->GetStreamByStreamId(streamId);
161     if (streamDesc == nullptr) {
162         MEDIA_LOG_E("UpdateDownloadFinished get stream null id: " PUBLIC_LOG_D32, streamId);
163         return;
164     }
165 
166     if (streamDesc->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
167         VideoSegmentDownloadFinished(streamId);
168         return;
169     }
170 
171     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloader(streamId);
172     if (segmentDownloader == nullptr) {
173         MEDIA_LOG_E("GetSegmentDownloader failed when UpdateDownloadFinished, streamId " PUBLIC_LOG_D32, streamId);
174         return;
175     }
176 
177     std::shared_ptr<DashSegment> seg;
178     DashMpdGetRet getRet = mpdDownloader_->GetNextSegmentByStreamId(streamId, seg);
179     MEDIA_LOG_I("GetNextSegmentByStreamId " PUBLIC_LOG_D32 ", ret=" PUBLIC_LOG_D32, streamId, getRet);
180     if (seg != nullptr) {
181         segmentDownloader->Open(seg);
182     } else if (getRet == DASH_MPD_GET_FINISH) {
183         segmentDownloader->SetAllSegmentFinished();
184     }
185 }
186 
PostBufferingEvent(int streamId,BufferingInfoType type)187 void DashMediaDownloader::PostBufferingEvent(int streamId, BufferingInfoType type)
188 {
189     if (callback_ == nullptr || mpdDownloader_ == nullptr) {
190         MEDIA_LOG_I("PostBufferingEvent streamId: " PUBLIC_LOG_D32 " type: " PUBLIC_LOG_D32, streamId, type);
191         return;
192     }
193 
194     std::shared_ptr<DashStreamDescription> streamDesc = mpdDownloader_->GetStreamByStreamId(streamId);
195     if (streamDesc == nullptr || streamDesc->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
196         return;
197     }
198 
199     if (type == BufferingInfoType::BUFFERING_PERCENT) {
200         uint32_t percent = 0;
201         for (auto &downloader : segmentDownloaders_) {
202             if (downloader == nullptr || downloader->GetStreamType() == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
203                 continue;
204             }
205 
206             uint32_t segPercent = downloader->GetCachedPercent();
207             percent = (percent == 0 || segPercent < percent) ? segPercent : percent;
208         }
209         if (percent > 0 && percent < BUFFERING_PERCENT_FULL && lastBufferingPercent_ != percent) {
210             MEDIA_LOG_I("PostBufferingEvent buffering percent " PUBLIC_LOG_U32, percent);
211             callback_->OnEvent({PluginEventType::EVENT_BUFFER_PROGRESS, {percent}, "buffer percent"});
212             lastBufferingPercent_ = percent;
213         }
214         return;
215     }
216 
217     // ensure the order of the buffering_start and buffering_end, must use lock, this lock can not use in other scene
218     // OnEvent can not block and lock other resource
219     std::lock_guard<std::mutex> bufferingLock(bufferingMutex_);
220     // audio or video buffering start will post event, audio and video buffering end will post event
221     uint32_t flag =
222         streamDesc->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID ? VIDEO_BUFFERING_FLAG : AUDIO_BUFFERING_FLAG;
223     if (type == BufferingInfoType::BUFFERING_START) {
224         if (bufferingFlag_ == 0) {
225             MEDIA_LOG_I("PostBufferingEvent buffering start");
226             callback_->OnEvent({PluginEventType::BUFFERING_START, {BufferingInfoType::BUFFERING_START}, "start"});
227             callback_->OnEvent({PluginEventType::EVENT_BUFFER_PROGRESS, {0}, "buffer percent"});
228         }
229         bufferingFlag_ |= flag;
230         return;
231     } else if (type == BufferingInfoType::BUFFERING_END) {
232         uint32_t lastBufferingFlag = bufferingFlag_;
233         if ((bufferingFlag_ & flag) > 0) {
234             bufferingFlag_ ^= flag;
235         }
236         if (lastBufferingFlag > 0 && bufferingFlag_ == 0) {
237             MEDIA_LOG_I("PostBufferingEvent buffering end");
238             callback_->OnEvent({PluginEventType::EVENT_BUFFER_PROGRESS, {BUFFERING_PERCENT_FULL}, "buffer percent"});
239             callback_->OnEvent({PluginEventType::BUFFERING_END, {BufferingInfoType::BUFFERING_END}, "end"});
240         }
241         return;
242     }
243 }
244 
SeekToTime(int64_t seekTime,SeekMode mode)245 bool DashMediaDownloader::SeekToTime(int64_t seekTime, SeekMode mode)
246 {
247     MEDIA_LOG_I("DashMediaDownloader SeekToTime: " PUBLIC_LOG_D64, seekTime);
248     SeekToTs(seekTime);
249     return true;
250 }
251 
GetContentLength() const252 size_t DashMediaDownloader::GetContentLength() const
253 {
254     return 0;
255 }
256 
GetDuration() const257 int64_t DashMediaDownloader::GetDuration() const
258 {
259     MEDIA_LOG_I("DashMediaDownloader GetDuration " PUBLIC_LOG_D64, mpdDownloader_->GetDuration());
260     return mpdDownloader_->GetDuration();
261 }
262 
GetSeekable() const263 Seekable DashMediaDownloader::GetSeekable() const
264 {
265     MEDIA_LOG_I("DashMediaDownloader GetSeekable begin");
266     Seekable value = mpdDownloader_->GetSeekable();
267     if (value == Seekable::INVALID) {
268         return value;
269     }
270 
271     size_t times = 0;
272     bool status = false;
273     while (!status && times < RETRY_TIMES && !isInterruptNeeded_) {
274         for (auto downloader : segmentDownloaders_) {
275             status = downloader->GetStartedStatus();
276             if (!status) {
277                 break;
278             }
279         }
280         OSAL::SleepFor(SLEEP_TIME);
281         times++;
282     }
283 
284     if (times >= RETRY_TIMES || isInterruptNeeded_) {
285         MEDIA_LOG_I("DashMediaDownloader GetSeekable INVALID");
286         return Seekable::INVALID;
287     }
288 
289     MEDIA_LOG_I("DashMediaDownloader GetSeekable end");
290     return value;
291 }
292 
SetCallback(Callback * cb)293 void DashMediaDownloader::SetCallback(Callback* cb)
294 {
295     callback_ = cb;
296 }
297 
GetStartedStatus()298 bool DashMediaDownloader::GetStartedStatus()
299 {
300     return true;
301 }
302 
SetStatusCallback(StatusCallbackFunc cb)303 void DashMediaDownloader::SetStatusCallback(StatusCallbackFunc cb)
304 {
305     statusCallback_ = cb;
306     mpdDownloader_->SetStatusCallback(cb);
307 }
308 
GetBitRates()309 std::vector<uint32_t> DashMediaDownloader::GetBitRates()
310 {
311     return mpdDownloader_->GetBitRates();
312 }
313 
SelectBitRate(uint32_t bitrate)314 bool DashMediaDownloader::SelectBitRate(uint32_t bitrate)
315 {
316     std::lock_guard<std::mutex> sidxLock(parseSidxMutex_);
317     MEDIA_LOG_I("Dash SelectBitRate bitrate:" PUBLIC_LOG_U32, bitrate);
318     {
319         isAutoSelectBitrate_ = false;
320 
321         std::lock_guard<std::mutex> lock(switchMutex_);
322         // The bit rate is being switched. Wait until the sidx download and parsing are complete.
323         if (bitrateParam_.waitSidxFinish_ ||
324             trackParam_.waitSidxFinish_) {
325             // Save the target stream information and update the downloaded stream information
326             // when the callback indicating that the sidx parsing is complete is received.
327             MEDIA_LOG_I("wait last switch bitrate or track:" PUBLIC_LOG_U32 " sidx parse finish, switch type:"
328                 PUBLIC_LOG_D32, bitrateParam_.bitrate_, (int) bitrateParam_.type_);
329             preparedAction_.preparedBitrateParam_.bitrate_ = bitrate;
330             preparedAction_.preparedBitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_SMOOTH;
331             return true;
332         }
333 
334         bitrateParam_.bitrate_ = bitrate;
335         bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_SMOOTH;
336         bitrateParam_.waitSidxFinish_ = true;
337     }
338 
339     int64_t remainLastNumberSeq = -1;
340     bool bufferCleanFlag = true;
341     CleanVideoSegmentBuffer(bufferCleanFlag, remainLastNumberSeq);
342 
343     return SelectBitrateInternal(bufferCleanFlag, remainLastNumberSeq);
344 }
345 
SelectStream(int32_t streamId)346 Status DashMediaDownloader::SelectStream(int32_t streamId)
347 {
348     MEDIA_LOG_I("Dash SelectStream streamId:" PUBLIC_LOG_D32, streamId);
349     std::shared_ptr<DashStreamDescription> streamDesc = mpdDownloader_->GetStreamByStreamId(streamId);
350     if (streamDesc == nullptr) {
351         MEDIA_LOG_W("Dash SelectStream can not find streamId");
352         return Status::ERROR_INVALID_PARAMETER;
353     }
354 
355     if (streamDesc->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_AUD) {
356         return SelectAudio(streamDesc);
357     } else if (streamDesc->type_ == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE) {
358         return SelectSubtitle(streamDesc);
359     } else {
360         SelectBitRate(streamDesc->bandwidth_);
361         return Status::OK;
362     }
363 }
364 
SeekToTs(int64_t seekTime)365 void DashMediaDownloader::SeekToTs(int64_t seekTime)
366 {
367     int64_t seekTimeMs;
368     std::lock_guard<std::mutex> lock(parseSidxMutex_);
369     {
370         if (seekTime < 0 || seekTime > mpdDownloader_->GetDuration()) {
371             return;
372         }
373         seekTimeMs = seekTime / MS_2_NS;
374         if (preparedAction_.seekPosition_ != -1 ||
375             bitrateParam_.waitSidxFinish_ ||
376             trackParam_.waitSidxFinish_) {
377             preparedAction_.seekPosition_ = seekTimeMs;
378             MEDIA_LOG_I("SeekToTs:" PUBLIC_LOG_D64 ", wait sidx finish, bitrate:" PUBLIC_LOG_U32 ", type:"
379                 PUBLIC_LOG_D32, preparedAction_.seekPosition_, bitrateParam_.bitrate_, (int) bitrateParam_.type_);
380 
381             for (auto &segmentDownloader : segmentDownloaders_) {
382                 MEDIA_LOG_I("Dash clean streamId: " PUBLIC_LOG_D32, segmentDownloader->GetStreamId());
383                 int64_t remainLastNumberSeq = -1;
384                 segmentDownloader->CleanSegmentBuffer(true, remainLastNumberSeq);
385             }
386 
387             return;
388         }
389     }
390 
391     SeekInternal(seekTimeMs);
392 }
393 
SetIsTriggerAutoMode(bool isAuto)394 void DashMediaDownloader::SetIsTriggerAutoMode(bool isAuto)
395 {
396     isAutoSelectBitrate_ = isAuto;
397 }
398 
SetDownloadErrorState()399 void DashMediaDownloader::SetDownloadErrorState()
400 {
401     MEDIA_LOG_I("Dash SetDownloadErrorState");
402     if (callback_) {
403         callback_->OnEvent({PluginEventType::CLIENT_ERROR, {NetworkClientErrorCode::ERROR_TIME_OUT}, "download"});
404     }
405     downloadErrorState_ = true;
406 }
407 
SetPlayStrategy(const std::shared_ptr<PlayStrategy> & playStrategy)408 void DashMediaDownloader::SetPlayStrategy(const std::shared_ptr<PlayStrategy>& playStrategy)
409 {
410     if (playStrategy != nullptr) {
411         mpdDownloader_->SetHdrStart(playStrategy->preferHDR);
412         mpdDownloader_->SetInitResolution(playStrategy->width, playStrategy->height);
413         mpdDownloader_->SetDefaultLang(playStrategy->audioLanguage, MediaAVCodec::MediaType::MEDIA_TYPE_AUD);
414         mpdDownloader_->SetDefaultLang(playStrategy->subtitleLanguage, MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE);
415         expectDuration_ = static_cast<uint64_t>(playStrategy->duration);
416         bufferDurationForPlaying_ = playStrategy->bufferDurationForPlaying;
417     }
418 }
419 
GetStreamInfo(std::vector<StreamInfo> & streams)420 Status DashMediaDownloader::GetStreamInfo(std::vector<StreamInfo>& streams)
421 {
422     GetSeekable();
423     return mpdDownloader_->GetStreamInfo(streams);
424 }
425 
OnMpdInfoUpdate(DashMpdEvent mpdEvent)426 void DashMediaDownloader::OnMpdInfoUpdate(DashMpdEvent mpdEvent)
427 {
428     switch (mpdEvent) {
429         case DASH_MPD_EVENT_STREAM_INIT:
430             ReceiveMpdStreamInitEvent();
431             break;
432         case DASH_MPD_EVENT_PARSE_OK:
433             ReceiveMpdParseOkEvent();
434             break;
435         default:
436             break;
437     }
438 }
439 
ReceiveMpdStreamInitEvent()440 void DashMediaDownloader::ReceiveMpdStreamInitEvent()
441 {
442     MEDIA_LOG_I("Dash ReceiveMpdStreamInitEvent");
443     std::vector<StreamInfo> streams;
444     mpdDownloader_->GetStreamInfo(streams);
445     std::shared_ptr<DashStreamDescription> streamDesc = nullptr;
446     for (unsigned int index = 0; index < streams.size(); index++) {
447         streamDesc = mpdDownloader_->GetStreamByStreamId(streams[index].streamId);
448         if (streamDesc != nullptr && streamDesc->inUse_) {
449             std::shared_ptr<DashSegment> seg = nullptr;
450             if (breakpoint_ > 0) {
451                 mpdDownloader_->GetBreakPointSegment(streamDesc->streamId_, breakpoint_, seg);
452             } else {
453                 mpdDownloader_->GetNextSegmentByStreamId(streamDesc->streamId_, seg);
454             }
455 
456             if (seg == nullptr) {
457                 MEDIA_LOG_W("Dash get segment null in streamId " PUBLIC_LOG_D32, streamDesc->streamId_);
458                 continue;
459             }
460 
461             OpenInitSegment(streamDesc, seg);
462         }
463     }
464 }
465 
OpenInitSegment(const std::shared_ptr<DashStreamDescription> & streamDesc,const std::shared_ptr<DashSegment> & seg)466 void DashMediaDownloader::OpenInitSegment(
467     const std::shared_ptr<DashStreamDescription> &streamDesc, const std::shared_ptr<DashSegment> &seg)
468 {
469     std::shared_ptr<DashSegmentDownloader> downloader = std::make_shared<DashSegmentDownloader>(
470         callback_, streamDesc->streamId_, streamDesc->type_, expectDuration_, sourceLoader_);
471     if (statusCallback_ != nullptr) {
472         downloader->SetStatusCallback(statusCallback_);
473     }
474     auto doneCallback = [this] (int streamId) {
475         UpdateDownloadFinished(streamId);
476     };
477     downloader->SetDownloadDoneCallback(doneCallback);
478     auto bufferingCallback = [this] (int streamId, BufferingInfoType type) {
479         PostBufferingEvent(streamId, type);
480     };
481     downloader->SetSegmentBufferingCallback(bufferingCallback);
482     segmentDownloaders_.push_back(downloader);
483     std::shared_ptr<DashInitSegment> initSeg = mpdDownloader_->GetInitSegmentByStreamId(
484         streamDesc->streamId_);
485     if (initSeg != nullptr) {
486         downloader->SetInitSegment(initSeg);
487     }
488     downloader->SetDurationForPlaying(bufferDurationForPlaying_);
489     downloader->Open(seg);
490     MEDIA_LOG_I("dash first get segment in streamId " PUBLIC_LOG_D32 ", type "
491         PUBLIC_LOG_D32, streamDesc->streamId_, streamDesc->type_);
492 }
493 
ReceiveMpdParseOkEvent()494 void DashMediaDownloader::ReceiveMpdParseOkEvent()
495 {
496     MEDIA_LOG_I("Dash ReceiveMpdParseOkEvent");
497     int streamId = -1;
498     {
499         std::lock_guard<std::mutex> lock(parseSidxMutex_);
500         if (bitrateParam_.waitSidxFinish_ ||
501             trackParam_.waitSidxFinish_) {
502             UpdateSegmentIndexAfterSidxParseOk();
503 
504             if (DoPreparedAction(streamId)) {
505                 MEDIA_LOG_I("Dash DoPreparedAction, no need download segment");
506                 return;
507             }
508         } else {
509             MEDIA_LOG_I("switch type: " PUBLIC_LOG_D32 " or waitSidxFinish: "
510                 PUBLIC_LOG_D32 " is error ", bitrateParam_.waitSidxFinish_, bitrateParam_.type_);
511             return;
512         }
513     }
514 
515     GetSegmentToDownload(streamId, true);
516 }
517 
VideoSegmentDownloadFinished(int streamId)518 void DashMediaDownloader::VideoSegmentDownloadFinished(int streamId)
519 {
520     MEDIA_LOG_I("VideoSegmentDownloadFinished streamId:" PUBLIC_LOG_D32 ", type:"
521         PUBLIC_LOG_U32, streamId, bitrateParam_.type_);
522     int downloadStreamId = streamId;
523     {
524         std::lock_guard<std::mutex> lock(switchMutex_);
525         if (bitrateParam_.type_ != DASH_MPD_SWITCH_TYPE_NONE) {
526             // no need to auto switch
527             if (bitrateParam_.waitSegmentFinish_) {
528                 bitrateParam_.waitSegmentFinish_  = false;
529             } else {
530                 MEDIA_LOG_I("old segment download finish, should get next segment in select bitrate");
531                 return;
532             }
533 
534             if (bitrateParam_.waitSidxFinish_) {
535                 MEDIA_LOG_I("wait sidx download finish, should not get next segment");
536                 return;
537             }
538 
539             downloadStreamId = bitrateParam_.streamId_;
540             ResetBitrateParam();
541         } else {
542             // auto switch
543             bool switchFlag = true;
544             if (callback_ != nullptr) {
545                 switchFlag = callback_->CanAutoSelectBitRate();
546             }
547             std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(
548                 MediaAVCodec::MediaType::MEDIA_TYPE_VID);
549             if (segmentDownloader != nullptr && !segmentDownloader->IsAllSegmentFinished() &&
550                 switchFlag && isAutoSelectBitrate_) {
551                 bool flag = CheckAutoSelectBitrate(streamId);
552                 if (callback_ != nullptr) {
553                     callback_->SetSelectBitRateFlag(flag, bitrateParam_.bitrate_);
554                 }
555                 if (flag) {
556                     // switch success
557                     return;
558                 }
559             }
560         }
561     }
562 
563     GetSegmentToDownload(downloadStreamId, downloadStreamId != streamId);
564 }
565 
GetSegmentToDownload(int downloadStreamId,bool streamSwitchFlag)566 void DashMediaDownloader::GetSegmentToDownload(int downloadStreamId, bool streamSwitchFlag)
567 {
568     MEDIA_LOG_I("GetSegmentToDownload streamId: " PUBLIC_LOG_D32 ", streamSwitchFlag: "
569         PUBLIC_LOG_D32, downloadStreamId, streamSwitchFlag);
570     // segment list is ok and no segment is downloading in segmentDownloader, so get next segment to download
571     std::shared_ptr<DashSegment> segment = nullptr;
572     DashMpdGetRet ret = mpdDownloader_->GetNextSegmentByStreamId(downloadStreamId, segment);
573     if (ret == DASH_MPD_GET_ERROR) {
574         return;
575     }
576 
577     std::shared_ptr<DashStreamDescription> stream = mpdDownloader_->GetStreamByStreamId(downloadStreamId);
578     if (stream == nullptr) {
579         MEDIA_LOG_E("GetSegmentToDownload streamId: " PUBLIC_LOG_D32 " get stream is null", downloadStreamId);
580         return;
581     }
582 
583     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(stream->type_);
584     if (segmentDownloader == nullptr) {
585         return;
586     }
587 
588     if (streamSwitchFlag) {
589         MEDIA_LOG_I("switch stream update streamId from " PUBLIC_LOG_D32 " to "
590             PUBLIC_LOG_D32, segmentDownloader->GetStreamId(), downloadStreamId);
591         segmentDownloader->UpdateStreamId(downloadStreamId);
592 
593         std::shared_ptr<DashInitSegment> initSeg = mpdDownloader_->GetInitSegmentByStreamId(downloadStreamId);
594         if (initSeg != nullptr) {
595             segmentDownloader->SetInitSegment(initSeg);
596         }
597     }
598 
599     if (segment != nullptr) {
600         segmentDownloader->Open(segment);
601     } else if (ret == DASH_MPD_GET_FINISH) {
602         segmentDownloader->SetAllSegmentFinished();
603     }
604 }
605 
CleanVideoSegmentBuffer(bool & bufferCleanFlag,int64_t & remainLastNumberSeq)606 void DashMediaDownloader::CleanVideoSegmentBuffer(bool &bufferCleanFlag, int64_t &remainLastNumberSeq)
607 {
608     std::shared_ptr<DashSegmentDownloader> segmentDownloader;
609     auto iter = std::find_if(segmentDownloaders_.begin(), segmentDownloaders_.end(),
610         [&](const std::shared_ptr<DashSegmentDownloader> &downloader) {
611             return downloader->GetStreamType() == MediaAVCodec::MEDIA_TYPE_VID;
612         });
613     if (iter != segmentDownloaders_.end()) {
614         segmentDownloader = *iter;
615     }
616 
617     if (segmentDownloader == nullptr) {
618         MEDIA_LOG_W("Dash not start, can not SelectBitRate.");
619         return;
620     }
621 
622     remainLastNumberSeq = -1;
623     bufferCleanFlag = true;
624     // 1. clean segment buffer, get switch segment sequence. segment is in downloading or no segment buffer
625     if (!segmentDownloader->CleanSegmentBuffer(false, remainLastNumberSeq) &&
626         !segmentDownloader->IsSegmentFinish()) {
627         MEDIA_LOG_I("Dash SelectBitRate no need clean buffer, wait current segment download finish");
628         bufferCleanFlag = false;
629     }
630 }
631 
SelectBitrateInternal(bool bufferCleanFlag,int64_t remainLastNumberSeq)632 bool DashMediaDownloader::SelectBitrateInternal(bool bufferCleanFlag, int64_t remainLastNumberSeq)
633 {
634     std::lock_guard<std::mutex> lock(switchMutex_);
635     MEDIA_LOG_I("Dash SelectBitrateInternal remainLastNumberSeq:" PUBLIC_LOG_D64, remainLastNumberSeq);
636 
637     // 2. switch to destination bitrate
638     bitrateParam_.position_ = remainLastNumberSeq; // update by segment sequence, -1 means no segment downloading
639 
640     if (!bufferCleanFlag) {
641         bitrateParam_.waitSegmentFinish_ = true;
642     } else {
643         bitrateParam_.waitSegmentFinish_ = false;
644     }
645 
646     DashMpdGetRet ret = mpdDownloader_->GetNextVideoStream(bitrateParam_, bitrateParam_.streamId_);
647     if (ret == DASH_MPD_GET_ERROR) {
648         MEDIA_LOG_W("Dash SelectBitRate Stream:" PUBLIC_LOG_D32 " GetNextVideoStream failed.", bitrateParam_.streamId_);
649         return false;
650     }
651 
652     if (ret == DASH_MPD_GET_UNDONE) {
653         bitrateParam_.waitSidxFinish_ = true;
654         MEDIA_LOG_I("Dash SelectBitRate wait sidx finish");
655         return true;
656     } else {
657         bitrateParam_.waitSidxFinish_ = false;
658     }
659 
660     if (bitrateParam_.waitSegmentFinish_) {
661         std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(
662             MediaAVCodec::MediaType::MEDIA_TYPE_VID);
663         if (segmentDownloader == nullptr) {
664             MEDIA_LOG_W("SelectBitrateInternal can not get segmentDownloader.");
665             return false;
666         }
667 
668         if (!segmentDownloader->IsSegmentFinish()) {
669             return true;
670         }
671 
672         // old segment download finish, should get next segment
673         bitrateParam_.waitSegmentFinish_ = false;
674     }
675 
676     // 3. get dest segment and download
677     bitrateParam_.bitrate_ = 0;
678     bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_NONE;
679     GetSegmentToDownload(bitrateParam_.streamId_, true);
680     return true;
681 }
682 
CheckAutoSelectBitrate(int streamId)683 bool DashMediaDownloader::CheckAutoSelectBitrate(int streamId)
684 {
685     MEDIA_LOG_I("AutoSelectBitrate streamId: " PUBLIC_LOG_D32, streamId);
686     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(
687         MediaAVCodec::MediaType::MEDIA_TYPE_VID);
688     if (segmentDownloader == nullptr) {
689         MEDIA_LOG_W("AutoSelectBitrate can not get segmentDownloader.");
690         return false;
691     }
692     uint32_t desBitrate = GetNextBitrate(segmentDownloader);
693     if (desBitrate == 0) {
694         return false;
695     }
696     return AutoSelectBitrateInternal(desBitrate);
697 }
698 
GetNextBitrate(std::shared_ptr<DashSegmentDownloader> segmentDownloader)699 uint32_t DashMediaDownloader::GetNextBitrate(std::shared_ptr<DashSegmentDownloader> segmentDownloader)
700 {
701     std::shared_ptr<DashStreamDescription> stream = mpdDownloader_->GetUsingStreamByType(
702         MediaAVCodec::MediaType::MEDIA_TYPE_VID);
703     if (stream == nullptr) {
704         return 0;
705     }
706 
707     if (stream->videoType_ != DASH_VIDEO_TYPE_SDR) {
708         MEDIA_LOG_I("hdr stream no need to switch auto");
709         return 0;
710     }
711 
712     std::vector<uint32_t> bitRates =  mpdDownloader_->GetBitRatesByHdr(stream->videoType_ != DASH_VIDEO_TYPE_SDR);
713     if (bitRates.size() == 0) {
714         return 0;
715     }
716     uint32_t curBitrate = stream->bandwidth_;
717     uint64_t downloadSpeed = static_cast<uint64_t>(segmentDownloader->GetDownloadSpeed());
718     if (downloadSpeed == 0) {
719         return 0;
720     }
721     uint32_t desBitrate = GetDesBitrate(bitRates, downloadSpeed);
722     if (curBitrate == desBitrate) {
723         return 0;
724     }
725     uint32_t bufferLowSize =
726         static_cast<uint32_t>(static_cast<double>(curBitrate) / BYTE_TO_BIT * BUFFER_LOW_LIMIT);
727     // switch to high bitrate,if buffersize less than lowsize, do not switch
728     if (curBitrate < desBitrate && segmentDownloader->GetBufferSize()  < bufferLowSize) {
729         MEDIA_LOG_I("AutoSelectBitrate curBitrate " PUBLIC_LOG_D32 ", desBitRate " PUBLIC_LOG_D32
730             ", bufferLowSize " PUBLIC_LOG_D32, curBitrate, desBitrate, bufferLowSize);
731         return 0;
732     }
733     // high size: buffersize * 0.8
734     uint32_t bufferHighSize = segmentDownloader->GetRingBufferCapacity() * BUFFER_LIMIT_FACT;
735     // switch to low bitrate, if buffersize more than highsize, do not switch
736     if (curBitrate > desBitrate && segmentDownloader->GetBufferSize() > bufferHighSize) {
737         MEDIA_LOG_I("AutoSelectBitrate curBitrate " PUBLIC_LOG_D32 ", desBitRate " PUBLIC_LOG_D32
738             ", bufferHighSize " PUBLIC_LOG_D32, curBitrate, desBitrate, bufferHighSize);
739         return 0;
740     }
741     return desBitrate;
742 }
743 
AutoSelectBitrateInternal(uint32_t bitrate)744 bool DashMediaDownloader::AutoSelectBitrateInternal(uint32_t bitrate)
745 {
746     bitrateParam_.position_ = -1;
747     bitrateParam_.bitrate_ = bitrate;
748     bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_AUTO;
749     if (mpdDownloader_ == nullptr) {
750         return false;
751     }
752     DashMpdGetRet ret = mpdDownloader_->GetNextVideoStream(bitrateParam_, bitrateParam_.streamId_);
753     if (ret == DASH_MPD_GET_ERROR) {
754         return false;
755     }
756     if (ret == DASH_MPD_GET_UNDONE) {
757         bitrateParam_.waitSidxFinish_ = true;
758         return true;
759     }
760     bitrateParam_.bitrate_ = bitrate;
761     bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_NONE;
762     GetSegmentToDownload(bitrateParam_.streamId_, true);
763     return true;
764 }
765 
IsSeekingInSwitch()766 bool DashMediaDownloader::IsSeekingInSwitch()
767 {
768     std::lock_guard<std::mutex> lock(switchMutex_);
769     bool isSwitching = false;
770     if (bitrateParam_.type_ != DASH_MPD_SWITCH_TYPE_NONE) {
771         MEDIA_LOG_I("IsSeekingInSwitch streamId:" PUBLIC_LOG_D32 ", switching bitrate:"
772             PUBLIC_LOG_U32 ", type:" PUBLIC_LOG_D32, bitrateParam_.streamId_, bitrateParam_.bitrate_,
773             (int) bitrateParam_.type_);
774         int streamId = bitrateParam_.streamId_;
775         std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(
776             MediaAVCodec::MediaType::MEDIA_TYPE_VID);
777         if (segmentDownloader != nullptr && segmentDownloader->GetStreamId() != streamId) {
778             segmentDownloader->UpdateStreamId(streamId);
779         }
780 
781         ResetBitrateParam();
782         isSwitching = true;
783     }
784 
785     if (trackParam_.waitSidxFinish_) {
786         MEDIA_LOG_I("IsSeekingInSwitch track streamId:" PUBLIC_LOG_D32 ", waitSidxFinish_:"
787             PUBLIC_LOG_D32, trackParam_.streamId_, trackParam_.waitSidxFinish_);
788         int streamId = trackParam_.streamId_;
789         std::shared_ptr<DashStreamDescription> streamDesc = mpdDownloader_->GetStreamByStreamId(streamId);
790         if (streamDesc != nullptr) {
791             std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloaderByType(streamDesc->type_);
792             if (segmentDownloader != nullptr && segmentDownloader->GetStreamId() != streamId) {
793                 segmentDownloader->UpdateStreamId(streamId);
794             }
795             ResetTrackParam();
796             isSwitching = true;
797         }
798     }
799 
800     return isSwitching;
801 }
802 
HandleSeekReady(int32_t streamType,int32_t streamId,int64_t seekTimeMs,int32_t isEos)803 void DashMediaDownloader::HandleSeekReady(int32_t streamType, int32_t streamId, int64_t seekTimeMs, int32_t isEos)
804 {
805     Format seekReadyInfo {};
806     seekReadyInfo.PutIntValue("currentStreamType", streamType);
807     seekReadyInfo.PutIntValue("currentStreamId", streamId);
808     seekReadyInfo.PutLongValue("seekTime", seekTimeMs);
809     seekReadyInfo.PutIntValue("isEOS", isEos);
810     MEDIA_LOG_D("StreamType: " PUBLIC_LOG_D32 " StreamId: " PUBLIC_LOG_D32
811         " seekTime: " PUBLIC_LOG_D64 " isEOS: " PUBLIC_LOG_D32, streamType, streamId, seekTimeMs, isEos);
812     if (callback_ != nullptr) {
813         MEDIA_LOG_D("Onevent dash seek ready");
814         callback_->OnEvent({PluginEventType::DASH_SEEK_READY, seekReadyInfo, "dash_seek_ready"});
815     }
816 }
817 
GetVideoSeekTime(int64_t seekTimeMs)818 int64_t DashMediaDownloader::GetVideoSeekTime(int64_t seekTimeMs)
819 {
820     auto videoSegmentDownloader = GetSegmentDownloaderByType(MediaAVCodec::MediaType::MEDIA_TYPE_VID);
821     FALSE_RETURN_V_NOLOG(videoSegmentDownloader != nullptr, seekTimeMs);
822 
823     std::shared_ptr<DashSegment> segment;
824     return mpdDownloader_->SeekToTs(videoSegmentDownloader->GetStreamId(), seekTimeMs, segment);
825 }
826 
SeekInternal(int64_t seekTimeMs)827 void DashMediaDownloader::SeekInternal(int64_t seekTimeMs)
828 {
829     bool isSwitching = IsSeekingInSwitch();
830 
831     seekTimeMs = GetVideoSeekTime(seekTimeMs);
832     for (auto &segmentDownloader : segmentDownloaders_) {
833         std::shared_ptr<DashSegment> segment;
834         int32_t streamId = static_cast<int32_t>(segmentDownloader->GetStreamId());
835         mpdDownloader_->SeekToTs(segmentDownloader->GetStreamId(), seekTimeMs, segment);
836         if (segment == nullptr) {
837             MEDIA_LOG_I("Dash SeekToTs end streamId " PUBLIC_LOG_D32 ", type " PUBLIC_LOG_D32,
838                 segmentDownloader->GetStreamId(), segmentDownloader->GetStreamType());
839             int64_t remainLastNumberSeq = -1;
840             segmentDownloader->CleanSegmentBuffer(true, remainLastNumberSeq);
841             segmentDownloader->SetAllSegmentFinished();
842             HandleSeekReady(static_cast<int32_t>(segmentDownloader->GetStreamType()), streamId, seekTimeMs, 1);
843             continue;
844         }
845 
846         if (segmentDownloader->GetStreamType() == MediaAVCodec::MediaType::MEDIA_TYPE_VID &&
847             segmentDownloader->GetBufferSize() == 0 && seekTimeMs == 0) {
848             segmentDownloader->NotifyInitSuccess();
849         }
850         MEDIA_LOG_D("Dash SeekToTs segment " PUBLIC_LOG_D64 ", duration:"
851             PUBLIC_LOG_U32, segment->numberSeq_, segment->duration_);
852         std::shared_ptr<DashInitSegment> initSeg = mpdDownloader_->GetInitSegmentByStreamId(
853             segmentDownloader->GetStreamId());
854         if (!isSwitching && segmentDownloader->SeekToTime(segment, streamId)) {
855             MEDIA_LOG_I("Dash SeekToTs of buffered streamId " PUBLIC_LOG_D32 ", type " PUBLIC_LOG_D32,
856                 segmentDownloader->GetStreamId(), segmentDownloader->GetStreamType());
857             segmentDownloader->SetInitSegment(initSeg, true);
858         } else {
859             int64_t remainLastNumberSeq = -1;
860             segmentDownloader->CleanSegmentBuffer(true, remainLastNumberSeq);
861             mpdDownloader_->SetCurrentNumberSeqByStreamId(segmentDownloader->GetStreamId(), segment->numberSeq_);
862             segmentDownloader->SetInitSegment(initSeg, true);
863             segmentDownloader->Open(segment);
864         }
865         HandleSeekReady(static_cast<int32_t>(segmentDownloader->GetStreamType()), streamId, seekTimeMs, 0);
866     }
867 }
868 
SelectAudio(const std::shared_ptr<DashStreamDescription> & streamDesc)869 Status DashMediaDownloader::SelectAudio(const std::shared_ptr<DashStreamDescription> &streamDesc)
870 {
871     std::lock_guard<std::mutex> lock(parseSidxMutex_);
872     // stream track is being switched. Wait until the sidx download and parsing are complete.
873     if (bitrateParam_.waitSidxFinish_ ||
874         trackParam_.waitSidxFinish_) {
875         MEDIA_LOG_I("last bitrate switch: " PUBLIC_LOG_D32 " last track switch:"
876             PUBLIC_LOG_D32, bitrateParam_.waitSidxFinish_, trackParam_.waitSidxFinish_);
877         preparedAction_.preparedAudioParam_.streamId_ = streamDesc->streamId_;
878         return Status::OK;
879     }
880     return SelectAudioInternal(streamDesc);
881 }
882 
SelectAudioInternal(const std::shared_ptr<DashStreamDescription> & streamDesc)883 Status DashMediaDownloader::SelectAudioInternal(const std::shared_ptr<DashStreamDescription> &streamDesc)
884 {
885     MEDIA_LOG_I("SelectAudioInternal Stream:" PUBLIC_LOG_D32, streamDesc->streamId_);
886     std::shared_ptr<DashSegmentDownloader> downloader = GetSegmentDownloaderByType(streamDesc->type_);
887     if (downloader == nullptr) {
888         return Status::ERROR_UNKNOWN;
889     }
890 
891     int64_t remainLastNumberSeq = -1;
892     bool isEnd = false;
893 
894     // 1. clean segment buffer keep 1000 ms, get switch segment sequence and is segment receive finish flag.
895     downloader->CleanBufferByTime(remainLastNumberSeq, isEnd);
896 
897     std::lock_guard<std::mutex> lock(switchMutex_);
898     // 2. switch to destination stream
899     trackParam_.isEnd_ = isEnd;
900     trackParam_.type_ = MediaAVCodec::MediaType::MEDIA_TYPE_AUD;
901     trackParam_.streamId_ = streamDesc->streamId_;
902     trackParam_.position_ = remainLastNumberSeq; // update by segment sequence, -1 means no segment downloading
903 
904     DashMpdGetRet ret = mpdDownloader_->GetNextTrackStream(trackParam_);
905     if (ret == DASH_MPD_GET_ERROR) {
906         MEDIA_LOG_W("Dash SelectAudio Stream:" PUBLIC_LOG_D32 " failed.", trackParam_.streamId_);
907         return Status::ERROR_UNKNOWN;
908     }
909 
910     if (ret == DASH_MPD_GET_UNDONE) {
911         trackParam_.waitSidxFinish_ = true;
912         MEDIA_LOG_I("Dash SelectAudio wait sidx finish");
913         return Status::OK;
914     }
915 
916     // 3. get dest segment and download
917     GetSegmentToDownload(trackParam_.streamId_, true);
918     ResetTrackParam();
919     return Status::OK;
920 }
921 
SelectSubtitle(const std::shared_ptr<DashStreamDescription> & streamDesc)922 Status DashMediaDownloader::SelectSubtitle(const std::shared_ptr<DashStreamDescription> &streamDesc)
923 {
924     std::lock_guard<std::mutex> lock(parseSidxMutex_);
925     // stream track is being switched. Wait until the sidx download and parsing are complete.
926     if (bitrateParam_.waitSidxFinish_ ||
927         trackParam_.waitSidxFinish_) {
928         MEDIA_LOG_I("last bitrate switch: " PUBLIC_LOG_D32 " last track switch:"
929             PUBLIC_LOG_D32, bitrateParam_.waitSidxFinish_, trackParam_.waitSidxFinish_);
930         preparedAction_.preparedSubtitleParam_.streamId_ = streamDesc->streamId_;
931         return Status::OK;
932     }
933     return SelectSubtitleInternal(streamDesc);
934 }
935 
SelectSubtitleInternal(const std::shared_ptr<DashStreamDescription> & streamDesc)936 Status DashMediaDownloader::SelectSubtitleInternal(const std::shared_ptr<DashStreamDescription> &streamDesc)
937 {
938     MEDIA_LOG_I("SelectSubtitleInternal Stream:" PUBLIC_LOG_D32, streamDesc->streamId_);
939     std::shared_ptr<DashSegmentDownloader> downloader = GetSegmentDownloaderByType(streamDesc->type_);
940     if (downloader == nullptr) {
941         return Status::ERROR_UNKNOWN;
942     }
943 
944     int64_t remainLastNumberSeq = -1;
945 
946     // 1. clean all segment buffer, get switch segment sequence and is segment receive finish flag.
947     downloader->CleanSegmentBuffer(true, remainLastNumberSeq);
948 
949     std::lock_guard<std::mutex> lock(switchMutex_);
950     // 2. switch to destination stream
951     trackParam_.isEnd_ = false;
952     trackParam_.type_ = MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE;
953     trackParam_.streamId_ = streamDesc->streamId_;
954     trackParam_.position_ = remainLastNumberSeq; // update by segment sequence, -1 means no segment downloading
955 
956     DashMpdGetRet ret = mpdDownloader_->GetNextTrackStream(trackParam_);
957     if (ret == DASH_MPD_GET_ERROR) {
958         MEDIA_LOG_W("Dash SelectSubtitle Stream:" PUBLIC_LOG_D32 " failed.", trackParam_.streamId_);
959         return Status::ERROR_UNKNOWN;
960     }
961 
962     if (ret == DASH_MPD_GET_UNDONE) {
963         trackParam_.waitSidxFinish_ = true;
964         MEDIA_LOG_I("Dash SelectSubtitle wait sidx finish");
965         return Status::OK;
966     }
967 
968     // 3. get dest segment and download
969     GetSegmentToDownload(trackParam_.streamId_, true);
970     ResetTrackParam();
971     return Status::OK;
972 }
973 
DoPreparedSwitchBitrate(bool switchBitrateOk,bool & needDownload,int & streamId)974 bool DashMediaDownloader::DoPreparedSwitchBitrate(bool switchBitrateOk, bool &needDownload, int &streamId)
975 {
976     bool needSwitchBitrate = false;
977     {
978         std::lock_guard<std::mutex> lock(switchMutex_);
979         if (switchBitrateOk) {
980             if (!bitrateParam_.waitSegmentFinish_) {
981                 ResetBitrateParam();
982             } else {
983                 bitrateParam_.waitSidxFinish_ = false;
984                 // wait segment download finish, no need to download video segment
985                 MEDIA_LOG_I("SwitchBitrate sidx ok and need wait segment finish");
986                 needDownload = false;
987             }
988         } else {
989             ResetTrackParam();
990         }
991 
992         if (preparedAction_.preparedBitrateParam_.type_ != DASH_MPD_SWITCH_TYPE_NONE) {
993             ResetBitrateParam();
994             needSwitchBitrate = true;
995             bitrateParam_.bitrate_ = preparedAction_.preparedBitrateParam_.bitrate_;
996             bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_SMOOTH;
997             // keep wait sidx finish flag, avoid to reset bitrateParam after video segment download finish
998             bitrateParam_.waitSidxFinish_ = true;
999             preparedAction_.preparedBitrateParam_.bitrate_ = 0;
1000             preparedAction_.preparedBitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_NONE;
1001         }
1002     }
1003 
1004     if (needSwitchBitrate) {
1005         int64_t remainLastNumberSeq = -1;
1006         bool bufferCleanFlag = true;
1007         CleanVideoSegmentBuffer(bufferCleanFlag, remainLastNumberSeq);
1008         MEDIA_LOG_I("PreparedSwitchBitrate: " PUBLIC_LOG_U32, bitrateParam_.bitrate_);
1009         return SelectBitrateInternal(bufferCleanFlag, remainLastNumberSeq);
1010     }
1011 
1012     return false;
1013 }
1014 
DoPreparedSwitchAudio(int & streamId)1015 bool DashMediaDownloader::DoPreparedSwitchAudio(int &streamId)
1016 {
1017     if (preparedAction_.preparedAudioParam_.streamId_ != -1) {
1018         ResetTrackParam();
1019         std::shared_ptr<DashStreamDescription> streamDesc =
1020             mpdDownloader_->GetStreamByStreamId(preparedAction_.preparedAudioParam_.streamId_);
1021         MEDIA_LOG_I("PreparedSwitchAudio id:" PUBLIC_LOG_D32, preparedAction_.preparedAudioParam_.streamId_);
1022         preparedAction_.preparedAudioParam_.streamId_ = -1;
1023         if (streamDesc != nullptr && SelectAudioInternal(streamDesc) == Status::OK) {
1024             return true;
1025         }
1026     }
1027 
1028     return false;
1029 }
1030 
DoPreparedSwitchSubtitle(int & streamId)1031 bool DashMediaDownloader::DoPreparedSwitchSubtitle(int &streamId)
1032 {
1033     if (preparedAction_.preparedSubtitleParam_.streamId_ != -1) {
1034         ResetTrackParam();
1035         std::shared_ptr<DashStreamDescription> streamDesc =
1036             mpdDownloader_->GetStreamByStreamId(preparedAction_.preparedSubtitleParam_.streamId_);
1037         MEDIA_LOG_I("PreparedSwitchSubtitle id:" PUBLIC_LOG_D32, preparedAction_.preparedSubtitleParam_.streamId_);
1038         preparedAction_.preparedSubtitleParam_.streamId_ = -1;
1039 
1040         if (streamDesc != nullptr && SelectSubtitleInternal(streamDesc) == Status::OK) {
1041             return true;
1042         }
1043     }
1044 
1045     return false;
1046 }
1047 
DoPreparedSwitchAction(bool switchBitrateOk,bool switchAudioOk,bool switchSubtitleOk,int & streamId)1048 bool DashMediaDownloader::DoPreparedSwitchAction(bool switchBitrateOk,
1049     bool switchAudioOk, bool switchSubtitleOk, int &streamId)
1050 {
1051     bool segmentNeedDownload = true;
1052     // first should check switch bitrate
1053     if (DoPreparedSwitchBitrate(switchBitrateOk, segmentNeedDownload, streamId)) {
1054         // previous action is switch bitrate, no need to get segment when do prepare switch bitrate
1055         segmentNeedDownload = !switchBitrateOk;
1056         if (bitrateParam_.type_ != DASH_MPD_SWITCH_TYPE_NONE && bitrateParam_.waitSidxFinish_) {
1057             MEDIA_LOG_I("DoPreparedAction switch bitrate wait sidx finish:" PUBLIC_LOG_U32, bitrateParam_.bitrate_);
1058             return switchBitrateOk;
1059         }
1060     }
1061 
1062     if (DoPreparedSwitchAudio(streamId)) {
1063         // previous action is switch audio, no need to get segment when do prepare switch audio
1064         segmentNeedDownload = switchAudioOk ? false : segmentNeedDownload;
1065         if (trackParam_.waitSidxFinish_) {
1066             MEDIA_LOG_I("DoPreparedAction switch audio wait sidx finish:" PUBLIC_LOG_D32, trackParam_.streamId_);
1067             return switchAudioOk ? true : !segmentNeedDownload;
1068         }
1069     }
1070 
1071     if (DoPreparedSwitchSubtitle(streamId)) {
1072         // previous action is switch subtitle, no need to get segment when do prepare switch subtitle
1073         segmentNeedDownload = switchSubtitleOk ? false : segmentNeedDownload;
1074         if (trackParam_.waitSidxFinish_) {
1075             MEDIA_LOG_I("DoPreparedAction switch subtitle wait sidx finish:" PUBLIC_LOG_D32, trackParam_.streamId_);
1076             return switchSubtitleOk ? true : !segmentNeedDownload;
1077         }
1078     }
1079 
1080     int64_t seekPosition = -1;
1081     if (preparedAction_.seekPosition_ != -1) {
1082         seekPosition = preparedAction_.seekPosition_;
1083         preparedAction_.seekPosition_ = -1;
1084     }
1085 
1086     if (seekPosition > -1) {
1087         SeekInternal(seekPosition); // seek after switch ok
1088         return true;
1089     }
1090 
1091     return !segmentNeedDownload;
1092 }
1093 
DoPreparedAction(int & streamId)1094 bool DashMediaDownloader::DoPreparedAction(int &streamId)
1095 {
1096     bool switchBitrateOk = bitrateParam_.waitSidxFinish_;
1097     bool switchAudioOk = (trackParam_.waitSidxFinish_ && trackParam_.type_ == MediaAVCodec::MediaType::MEDIA_TYPE_AUD);
1098     bool switchSubtitleOk =
1099         (trackParam_.waitSidxFinish_ && trackParam_.type_ == MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE);
1100 
1101     streamId = switchBitrateOk ? bitrateParam_.streamId_ : trackParam_.streamId_;
1102     return DoPreparedSwitchAction(switchBitrateOk, switchAudioOk, switchSubtitleOk, streamId);
1103 }
1104 
UpdateSegmentIndexAfterSidxParseOk()1105 void DashMediaDownloader::UpdateSegmentIndexAfterSidxParseOk()
1106 {
1107     std::lock_guard<std::mutex> lock(switchMutex_);
1108     if (bitrateParam_.waitSidxFinish_ && bitrateParam_.nextSegTime_ > 0) {
1109         mpdDownloader_->UpdateCurrentNumberSeqByTime(mpdDownloader_->GetStreamByStreamId(bitrateParam_.streamId_),
1110             bitrateParam_.nextSegTime_);
1111         bitrateParam_.nextSegTime_ = 0;
1112     } else if (trackParam_.waitSidxFinish_ && trackParam_.nextSegTime_ > 0) {
1113         mpdDownloader_->UpdateCurrentNumberSeqByTime(mpdDownloader_->GetStreamByStreamId(trackParam_.streamId_),
1114             trackParam_.nextSegTime_);
1115         trackParam_.nextSegTime_ = 0;
1116     }
1117 }
1118 
ResetBitrateParam()1119 void DashMediaDownloader::ResetBitrateParam()
1120 {
1121     bitrateParam_.bitrate_ = 0;
1122     bitrateParam_.type_ = DASH_MPD_SWITCH_TYPE_NONE;
1123     bitrateParam_.streamId_ = -1;
1124     bitrateParam_.position_ = -1;
1125     bitrateParam_.nextSegTime_ = 0;
1126     bitrateParam_.waitSegmentFinish_ = false;
1127     bitrateParam_.waitSidxFinish_ = false;
1128 }
1129 
ResetTrackParam()1130 void DashMediaDownloader::ResetTrackParam()
1131 {
1132     trackParam_.waitSidxFinish_ = false;
1133     trackParam_.isEnd_ = false;
1134     trackParam_.streamId_ = -1;
1135     trackParam_.position_ = -1;
1136     trackParam_.nextSegTime_ = 0;
1137 }
1138 
OnDrmInfoChanged(const std::multimap<std::string,std::vector<uint8_t>> & drmInfos)1139 void DashMediaDownloader::OnDrmInfoChanged(const std::multimap<std::string, std::vector<uint8_t>>& drmInfos)
1140 {
1141     if (callback_ != nullptr) {
1142         callback_->OnEvent({PluginEventType::SOURCE_DRM_INFO_UPDATE, {drmInfos}, "drm_info_update"});
1143     }
1144 }
1145 
SetInterruptState(bool isInterruptNeeded)1146 void DashMediaDownloader::SetInterruptState(bool isInterruptNeeded)
1147 {
1148     isInterruptNeeded_ = isInterruptNeeded;
1149     mpdDownloader_->SetInterruptState(isInterruptNeeded);
1150     for (unsigned int index = 0; index < segmentDownloaders_.size(); index++) {
1151         segmentDownloaders_[index]->SetInterruptState(isInterruptNeeded);
1152     }
1153 }
1154 
SetCurrentBitRate(int32_t bitRate,int32_t streamID)1155 Status DashMediaDownloader::SetCurrentBitRate(int32_t bitRate, int32_t streamID)
1156 {
1157     MEDIA_LOG_I("SetCurrentBitRate stream: " PUBLIC_LOG_D32 " biteRate: " PUBLIC_LOG_D32, streamID, bitRate);
1158     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloader(streamID);
1159     if (segmentDownloader != nullptr) {
1160         segmentDownloader->SetCurrentBitRate(bitRate);
1161     }
1162     return Status::OK;
1163 }
1164 
SetDemuxerState(int32_t streamId)1165 void DashMediaDownloader::SetDemuxerState(int32_t streamId)
1166 {
1167     MEDIA_LOG_I("SetDemuxerState streamId: " PUBLIC_LOG_D32, streamId);
1168     std::shared_ptr<DashSegmentDownloader> segmentDownloader = GetSegmentDownloader(streamId);
1169     if (segmentDownloader != nullptr) {
1170         segmentDownloader->SetDemuxerState();
1171     }
1172 }
1173 
GetPlaybackInfo(PlaybackInfo & playbackInfo)1174 void DashMediaDownloader::GetPlaybackInfo(PlaybackInfo& playbackInfo)
1175 {
1176     if (segmentDownloaders_.empty()) {
1177         return ;
1178     }
1179     if (segmentDownloaders_[0] != nullptr) {
1180         segmentDownloaders_[0]->GetIp(playbackInfo.serverIpAddress);
1181     }
1182     bool DownloadFinishStateTmp = true;
1183     playbackInfo.averageDownloadRate = 0;
1184     for (size_t i = 0; i < segmentDownloaders_.size(); i++) {
1185         if (playbackInfo.averageDownloadRate < static_cast<int64_t>(segmentDownloaders_[i]->GetDownloadSpeed())) {
1186             playbackInfo.averageDownloadRate = static_cast<int64_t>(segmentDownloaders_[i]->GetDownloadSpeed());
1187             std::pair<int64_t, int64_t> recordData = segmentDownloaders_[i]->GetDownloadRecordData();
1188             playbackInfo.downloadRate = recordData.first;
1189             playbackInfo.bufferDuration = recordData.second;
1190         }
1191         DownloadFinishStateTmp = (DownloadFinishStateTmp && segmentDownloaders_[i]->GetDownloadFinishState());
1192     }
1193     playbackInfo.isDownloading = DownloadFinishStateTmp ? false : true;
1194 }
1195 
GetBufferSize() const1196 size_t DashMediaDownloader::GetBufferSize() const
1197 {
1198     std::shared_ptr<DashSegmentDownloader> segmentDownloader =
1199         GetSegmentDownloaderByType(MediaAVCodec::MediaType::MEDIA_TYPE_VID);
1200     if (segmentDownloader == nullptr) {
1201         MEDIA_LOG_W("GetBufferSize can not get segmentDownloader.");
1202         return 0;
1203     }
1204     return segmentDownloader->GetBufferSize();
1205 }
1206 
GetPlayable()1207 bool DashMediaDownloader::GetPlayable()
1208 {
1209     std::shared_ptr<DashSegmentDownloader> vidSegmentDownloader =
1210         GetSegmentDownloaderByType(MediaAVCodec::MediaType::MEDIA_TYPE_VID);
1211     std::shared_ptr<DashSegmentDownloader> audSegmentDownloader =
1212         GetSegmentDownloaderByType(MediaAVCodec::MediaType::MEDIA_TYPE_AUD);
1213     if (vidSegmentDownloader != nullptr && audSegmentDownloader != nullptr) {
1214         return !vidSegmentDownloader->GetBufferringStatus() && !audSegmentDownloader->GetBufferringStatus();
1215     } else if (vidSegmentDownloader != nullptr) {
1216         return !vidSegmentDownloader->GetBufferringStatus();
1217     } else if (audSegmentDownloader != nullptr) {
1218         return !audSegmentDownloader->GetBufferringStatus();
1219     } else {
1220         MEDIA_LOG_E("GetPlayable error.");
1221         return false;
1222     }
1223 }
1224 
GetBufferingTimeOut()1225 bool DashMediaDownloader::GetBufferingTimeOut()
1226 {
1227     return false;
1228 }
1229 
SetAppUid(int32_t appUid)1230 void DashMediaDownloader::SetAppUid(int32_t appUid)
1231 {
1232     for (size_t i = 0; i < segmentDownloaders_.size(); i++) {
1233         segmentDownloaders_[i]->SetAppUid(appUid);
1234     }
1235 }
1236 
NotifyInitSuccess()1237 void DashMediaDownloader::NotifyInitSuccess()
1238 {
1239     for (size_t i = 0; i < segmentDownloaders_.size(); i++) {
1240         if (segmentDownloaders_[i] != nullptr) {
1241             segmentDownloaders_[i]->NotifyInitSuccess();
1242         }
1243     }
1244 }
1245 
GetMemorySize()1246 uint64_t DashMediaDownloader::GetMemorySize()
1247 {
1248     uint64_t memorySize = 0;
1249     for (size_t i = 0; i < segmentDownloaders_.size(); i++) {
1250         if (segmentDownloaders_[i] != nullptr) {
1251             auto streamType = segmentDownloaders_[i]->GetStreamType();
1252             memorySize += static_cast<uint64_t>(segmentDownloaders_[i]->GetRingBufferInitSize(streamType));
1253         }
1254     }
1255     return memorySize;
1256 }
1257 
StopBufferring(bool isAppBackground)1258 Status DashMediaDownloader::StopBufferring(bool isAppBackground)
1259 {
1260     MEDIA_LOG_I("DashMediaDownloader:StopBufferring enter");
1261     for (size_t index = 0; index < segmentDownloaders_.size(); index++) {
1262         FALSE_RETURN_V(segmentDownloaders_[index] != nullptr, Status::ERROR_NULL_POINTER);
1263         segmentDownloaders_[index]->StopBufferring(isAppBackground);
1264     }
1265     return Status::OK;
1266 }
1267 }
1268 }
1269 }
1270 }
1271