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