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