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