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