• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 
16 #define HST_LOG_TAG "Source"
17 #define MEDIA_ATOMIC_ABILITY
18 
19 #include "avcodec_trace.h"
20 #include "cpp_ext/type_traits_ext.h"
21 #include "common/log.h"
22 #include "osal/utils/util.h"
23 #include "common/media_source.h"
24 #include "plugin/plugin_manager_v2.h"
25 #include "source.h"
26 
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "Source" };
29 }
30 
31 namespace OHOS {
32 namespace Media {
33 using namespace Plugins;
34 
35 static std::map<std::string, ProtocolType> g_protocolStringToType = {
36     {"http", ProtocolType::HTTP},
37     {"https", ProtocolType::HTTPS},
38     {"file", ProtocolType::FILE},
39     {"stream", ProtocolType::STREAM},
40     {"fd", ProtocolType::FD}
41 };
42 
Source()43 Source::Source()
44     : protocol_(),
45       uri_(),
46       seekable_(Seekable::INVALID),
47       plugin_(nullptr),
48       isPluginReady_(false),
49       isAboveWaterline_(false),
50       mediaDemuxerCallback_(std::make_shared<CallbackImpl>())
51 {
52     MEDIA_LOG_D("Source called");
53 }
54 
~Source()55 Source::~Source()
56 {
57     MEDIA_LOG_D("~Source called");
58     if (plugin_) {
59         plugin_->Deinit();
60     }
61 }
62 
SetCallback(Callback * callback)63 void Source::SetCallback(Callback* callback)
64 {
65     MEDIA_LOG_I("SetCallback entered.");
66     FALSE_RETURN_MSG(callback != nullptr, "callback is nullptr");
67     FALSE_RETURN_MSG(mediaDemuxerCallback_ != nullptr, "mediaDemuxerCallback is nullptr");
68     mediaDemuxerCallback_->SetCallbackWrap(callback);
69 }
70 
ClearData()71 void Source::ClearData()
72 {
73     protocol_.clear();
74     uri_.clear();
75     seekable_ = Seekable::INVALID;
76     isPluginReady_ = false;
77     isAboveWaterline_ = false;
78     seekToTimeFlag_ = false;
79 }
80 
SetSource(const std::shared_ptr<MediaSource> & source)81 Status Source::SetSource(const std::shared_ptr<MediaSource>& source)
82 {
83     MediaAVCodec::AVCodecTrace trace("Source::SetSource");
84     MEDIA_LOG_I("SetSource enter.");
85     FALSE_RETURN_V_MSG_E(source != nullptr, Status::ERROR_INVALID_PARAMETER, "SetSource invalid source");
86 
87     ClearData();
88     Status ret = FindPlugin(source);
89     FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SetSource FindPlugin failed");
90 
91     ret = InitPlugin(source);
92     FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SetSource InitPlugin failed");
93 
94     if (plugin_ != nullptr) {
95         seekToTimeFlag_ = plugin_->IsSeekToTimeSupported();
96     }
97     MEDIA_LOG_I("SetSource seekToTimeFlag: " PUBLIC_LOG_D32, seekToTimeFlag_);
98     MEDIA_LOG_I("SetSource exit.");
99     return Status::OK;
100 }
101 
SetBundleName(const std::string & bundleName)102 void Source::SetBundleName(const std::string& bundleName)
103 {
104     if (plugin_ != nullptr) {
105         MEDIA_LOG_I("SetBundleName bundleName: " PUBLIC_LOG_S, bundleName.c_str());
106         plugin_->SetBundleName(bundleName);
107     }
108 }
109 
SetDemuxerState(int32_t streamId)110 void Source::SetDemuxerState(int32_t streamId)
111 {
112     plugin_->SetDemuxerState(streamId);
113 }
114 
InitPlugin(const std::shared_ptr<MediaSource> & source)115 Status Source::InitPlugin(const std::shared_ptr<MediaSource>& source)
116 {
117     MediaAVCodec::AVCodecTrace trace("Source::InitPlugin");
118     MEDIA_LOG_I("InitPlugin enter");
119     FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "InitPlugin, Source plugin is nullptr!");
120 
121     Status ret = plugin_->Init();
122     FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "InitPlugin failed");
123 
124     plugin_->SetCallback(this);
125     plugin_->SetEnableOnlineFdCache(isEnableFdCache_);
126     ret = plugin_->SetSource(source);
127 
128     MEDIA_LOG_I("InitPlugin exit");
129     return ret;
130 }
131 
Prepare()132 Status Source::Prepare()
133 {
134     MEDIA_LOG_I("Prepare entered.");
135     if (plugin_ == nullptr) {
136         return Status::OK;
137     }
138     Status ret = plugin_->Prepare();
139     if (ret == Status::OK) {
140         MEDIA_LOG_D("media source send EVENT_READY");
141     } else if (ret == Status::ERROR_DELAY_READY) {
142         if (isAboveWaterline_) {
143             MEDIA_LOG_D("media source send EVENT_READY");
144             isPluginReady_ = false;
145             isAboveWaterline_ = false;
146         }
147     }
148     return ret;
149 }
150 
IsSeekToTimeSupported()151 bool Source::IsSeekToTimeSupported()
152 {
153     return seekToTimeFlag_;
154 }
155 
Start()156 Status Source::Start()
157 {
158     MEDIA_LOG_I("Start entered.");
159     return plugin_ ? plugin_->Start() : Status::ERROR_INVALID_OPERATION;
160 }
161 
GetBitRates(std::vector<uint32_t> & bitRates)162 Status Source::GetBitRates(std::vector<uint32_t>& bitRates)
163 {
164     MEDIA_LOG_I("GetBitRates");
165     if (plugin_ == nullptr) {
166         MEDIA_LOG_E("GetBitRates failed, plugin_ is nullptr");
167         return Status::ERROR_INVALID_OPERATION;
168     }
169     return plugin_->GetBitRates(bitRates);
170 }
171 
SelectBitRate(uint32_t bitRate)172 Status Source::SelectBitRate(uint32_t bitRate)
173 {
174     MEDIA_LOG_I("SelectBitRate");
175     if (plugin_ == nullptr) {
176         MEDIA_LOG_E("SelectBitRate failed, plugin_ is nullptr");
177         return Status::ERROR_INVALID_OPERATION;
178     }
179     return plugin_->SelectBitRate(bitRate);
180 }
181 
SetCurrentBitRate(int32_t bitRate,int32_t streamID)182 Status Source::SetCurrentBitRate(int32_t bitRate, int32_t streamID)
183 {
184     MEDIA_LOG_I("SetCurrentBitRate");
185     if (plugin_ == nullptr) {
186         MEDIA_LOG_E("SetCurrentBitRate failed, plugin_ is nullptr");
187         return Status::ERROR_INVALID_OPERATION;
188     }
189     return plugin_->SetCurrentBitRate(bitRate, streamID);
190 }
191 
SeekToTime(int64_t seekTime,SeekMode mode)192 Status Source::SeekToTime(int64_t seekTime, SeekMode mode)
193 {
194     if (seekable_ != Seekable::SEEKABLE) {
195         GetSeekable();
196     }
197     int64_t timeNs;
198     if (Plugins::Ms2HstTime(seekTime, timeNs)) {
199         return plugin_->SeekToTime(timeNs, mode);
200     } else {
201         return Status::ERROR_INVALID_PARAMETER;
202     }
203 }
204 
GetDownloadInfo(DownloadInfo & downloadInfo)205 Status Source::GetDownloadInfo(DownloadInfo& downloadInfo)
206 {
207     MEDIA_LOG_I("GetDownloadInfo");
208     if (plugin_ == nullptr) {
209         MEDIA_LOG_E("GetDownloadInfo failed, plugin_ is nullptr");
210         return Status::ERROR_INVALID_OPERATION;
211     }
212     return plugin_->GetDownloadInfo(downloadInfo);
213 }
214 
GetPlaybackInfo(PlaybackInfo & playbackInfo)215 Status Source::GetPlaybackInfo(PlaybackInfo& playbackInfo)
216 {
217     MEDIA_LOG_I("GetPlaybackInfo");
218     if (plugin_ == nullptr) {
219         MEDIA_LOG_E("GetPlaybackInfo  failed, plugin_ is nullptr");
220         return Status::ERROR_INVALID_OPERATION;
221     }
222     return plugin_->GetPlaybackInfo(playbackInfo);
223 }
224 
IsNeedPreDownload()225 bool Source::IsNeedPreDownload()
226 {
227     if (plugin_ == nullptr) {
228         MEDIA_LOG_E("IsNeedPreDownload failed, plugin_ is nullptr");
229         return false;
230     }
231     return plugin_->IsNeedPreDownload();
232 }
233 
Stop()234 Status Source::Stop()
235 {
236     MEDIA_LOG_I("Stop entered.");
237     seekable_ = Seekable::INVALID;
238     protocol_.clear();
239     uri_.clear();
240     return plugin_->Stop();
241 }
242 
Pause()243 Status Source::Pause()
244 {
245     MEDIA_LOG_I("Pause entered.");
246     if (plugin_ != nullptr) {
247         plugin_->Pause();
248     }
249     return Status::OK;
250 }
251 
Resume()252 Status Source::Resume()
253 {
254     MEDIA_LOG_I("Resume entered.");
255     if (plugin_ != nullptr) {
256         plugin_->Resume();
257     }
258     return Status::OK;
259 }
260 
SetReadBlockingFlag(bool isReadBlockingAllowed)261 Status Source::SetReadBlockingFlag(bool isReadBlockingAllowed)
262 {
263     MEDIA_LOG_D("SetReadBlockingFlag entered, IsReadBlockingAllowed %{public}d", isReadBlockingAllowed);
264     FALSE_RETURN_V(plugin_ != nullptr, Status::OK);
265     return plugin_->SetReadBlockingFlag(isReadBlockingAllowed);
266 }
267 
OnEvent(const Plugins::PluginEvent & event)268 void Source::OnEvent(const Plugins::PluginEvent& event)
269 {
270     MEDIA_LOG_D("OnEvent");
271     if (protocol_ == "http" && isInterruptNeeded_) {
272         MEDIA_LOG_I("http OnEvent isInterruptNeeded, return");
273         return;
274     }
275     if (event.type == PluginEventType::ABOVE_LOW_WATERLINE) {
276         if (isPluginReady_ && isAboveWaterline_) {
277             isPluginReady_ = false;
278             isAboveWaterline_ = false;
279         }
280         return;
281     }
282     FALSE_RETURN_MSG(mediaDemuxerCallback_ != nullptr, "mediaDemuxerCallback is nullptr");
283     if (event.type == PluginEventType::CLIENT_ERROR || event.type == PluginEventType::SERVER_ERROR) {
284         MEDIA_LOG_I("Error happened, need notify client by OnEvent");
285         mediaDemuxerCallback_->OnEvent(event);
286     } else if (event.type == PluginEventType::SOURCE_DRM_INFO_UPDATE) {
287         MEDIA_LOG_I("Drminfo updates from source");
288         mediaDemuxerCallback_->OnEvent(event);
289     } else if (event.type == PluginEventType::BUFFERING_END || event.type == PluginEventType::BUFFERING_START) {
290         MEDIA_LOG_I("Buffering start or end.");
291         mediaDemuxerCallback_->OnEvent(event);
292     } else if (event.type == PluginEventType::SOURCE_BITRATE_START) {
293         MEDIA_LOG_I("source bitrate start from source.");
294         mediaDemuxerCallback_->OnEvent(event);
295     } else if (event.type == PluginEventType::CACHED_DURATION) {
296         MEDIA_LOG_D("Onevent cached duration.");
297         mediaDemuxerCallback_->OnEvent(event);
298     } else if (event.type == PluginEventType::EVENT_BUFFER_PROGRESS) {
299         MEDIA_LOG_I("buffer percent update.");
300         mediaDemuxerCallback_->OnEvent(event);
301     } else if (event.type == PluginEventType::DASH_SEEK_READY) {
302         MEDIA_LOG_D("Onevent dash seek ready.");
303         mediaDemuxerCallback_->OnEvent(event);
304     } else {
305         MEDIA_LOG_I("on event type undefined.");
306     }
307 }
308 
SetSelectBitRateFlag(bool flag,uint32_t desBitRate)309 void Source::SetSelectBitRateFlag(bool flag, uint32_t desBitRate)
310 {
311     if (mediaDemuxerCallback_) {
312         mediaDemuxerCallback_->SetSelectBitRateFlag(flag, desBitRate);
313     }
314 }
315 
CanAutoSelectBitRate()316 bool Source::CanAutoSelectBitRate()
317 {
318     FALSE_RETURN_V_MSG_E(mediaDemuxerCallback_ != nullptr, false, "mediaDemuxerCallback_ is nullptr.");
319     return mediaDemuxerCallback_->CanAutoSelectBitRate();
320 }
321 
SetInterruptState(bool isInterruptNeeded)322 void Source::SetInterruptState(bool isInterruptNeeded)
323 {
324     isInterruptNeeded_ = isInterruptNeeded;
325     if (plugin_) {
326         plugin_->SetInterruptState(isInterruptNeeded_);
327     }
328 }
329 
GetSeekable()330 Plugins::Seekable Source::GetSeekable()
331 {
332     FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Plugins::Seekable::INVALID, "GetSeekable, Source plugin is nullptr");
333     int32_t retry {0};
334     seekable_ = Seekable::INVALID;
335     do {
336         seekable_ = plugin_->GetSeekable();
337         retry++;
338         if (seekable_ == Seekable::INVALID) {
339             if (retry >= 20) { // 20 means retry times
340                 break;
341             }
342             OSAL::SleepFor(10); // 10 means sleep time pre retry
343         }
344     } while (seekable_ == Seekable::INVALID);
345     return seekable_;
346 }
347 
GetUriSuffix(const std::string & uri)348 std::string Source::GetUriSuffix(const std::string& uri)
349 {
350     MEDIA_LOG_D("IN");
351     std::string suffix;
352     auto const pos = uri.find_last_of('.');
353     if (pos != std::string::npos) {
354         suffix = uri.substr(pos + 1);
355     }
356     return suffix;
357 }
358 
Read(int32_t streamID,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)359 Status Source::Read(int32_t streamID, std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
360 {
361     FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "ReadData, Source plugin is nullptr");
362     FALSE_RETURN_V(!perfRecEnabled_, ReadWithPerfRecord(streamID, buffer, offset, expectedLen));
363     if (seekToTimeFlag_) {
364         return plugin_->Read(streamID, buffer, offset, expectedLen);
365     }
366     return plugin_->Read(buffer, offset, expectedLen);
367 }
368 
SetPerfRecEnabled(bool perfRecEnabled)369 Status Source::SetPerfRecEnabled(bool perfRecEnabled)
370 {
371     perfRecEnabled_ = perfRecEnabled;
372     return Status::OK;
373 }
374 
ReadWithPerfRecord(int32_t streamID,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)375 Status Source::ReadWithPerfRecord(
376     int32_t streamID, std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
377 {
378     int64_t readDuration = 0;
379     Status readRes = Status::OK;
380     if (seekToTimeFlag_) {
381         readDuration = CALC_EXPR_TIME_MS(readRes = plugin_->Read(streamID, buffer, offset, expectedLen));
382     } else {
383         readDuration = CALC_EXPR_TIME_MS(readRes = plugin_->Read(buffer, offset, expectedLen));
384     }
385     int64_t readDurationUs = 0;
386     FALSE_RETURN_V_MSG(
387         Plugins::Ms2Us(readDuration, readDurationUs), readRes, "Invalid readDuration %{public}" PRId64, readDuration);
388     int64_t readSpeed = static_cast<int64_t>(expectedLen) / readDurationUs;
389     FALSE_RETURN_V_NOLOG(perfRecorder_.Record(readSpeed) == PerfRecorder::FULL, readRes);
390     FALSE_RETURN_V_MSG(mediaDemuxerCallback_ != nullptr, readRes, "Report perf failed, callback is nullptr");
391     mediaDemuxerCallback_->OnDfxEvent(
392         { .type = Plugins::PluginDfxEventType::PERF_SOURCE, .param = perfRecorder_.GetMainPerfData() });
393     perfRecorder_.Reset();
394     return readRes;
395 }
396 
SeekTo(uint64_t offset)397 Status Source::SeekTo(uint64_t offset)
398 {
399     FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "SeekTo, Source plugin is nullptr");
400     return plugin_->SeekTo(offset);
401 }
402 
GetStreamInfo(std::vector<StreamInfo> & streams)403 Status Source::GetStreamInfo(std::vector<StreamInfo>& streams)
404 {
405     FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION,
406         "GetStreamInfo, Source plugin is nullptr");
407     Status ret = plugin_->GetStreamInfo(streams);
408     if (ret == Status::OK && streams.size() == 0) {
409         MEDIA_LOG_I("GetStreamInfo empty, MIX Stream");
410         Plugins::StreamInfo info;
411         info.streamId = 0;
412         info.bitRate = 0;
413         info.type = Plugins::MIXED;
414         streams.push_back(info);
415     }
416     for (auto& iter : streams) {
417         MEDIA_LOG_I("Source GetStreamInfo id = " PUBLIC_LOG_D32 " type = " PUBLIC_LOG_D32,
418             iter.streamId, iter.type);
419     }
420     return ret;
421 }
422 
GetProtocolByUri()423 bool Source::GetProtocolByUri()
424 {
425     auto ret = true;
426     auto const pos = uri_.find("://");
427     if (pos != std::string::npos) {
428         auto prefix = uri_.substr(0, pos);
429         protocol_.append(prefix);
430     } else {
431         protocol_.append("file");
432         std::string fullPath;
433         ret = OSAL::ConvertFullPath(uri_, fullPath); // convert path to full path
434         if (ret && !fullPath.empty()) {
435             uri_ = fullPath;
436         }
437     }
438     return ret;
439 }
440 
ParseProtocol(const std::shared_ptr<MediaSource> & source)441 bool Source::ParseProtocol(const std::shared_ptr<MediaSource>& source)
442 {
443     bool ret = true;
444     SourceType srcType = source->GetSourceType();
445     MEDIA_LOG_D("sourceType = " PUBLIC_LOG_D32, CppExt::to_underlying(srcType));
446     if (srcType == SourceType::SOURCE_TYPE_URI) {
447         uri_ = source->GetSourceUri();
448         std::string mimeType = source->GetMimeType();
449         if (mimeType == AVMimeTypes::APPLICATION_M3U8) {
450             protocol_ = "http";
451         } else {
452             ret = GetProtocolByUri();
453         }
454     } else if (srcType == SourceType::SOURCE_TYPE_FD) {
455         protocol_.append("fd");
456         uri_ = source->GetSourceUri();
457     } else if (srcType == SourceType::SOURCE_TYPE_STREAM) {
458         protocol_.append("stream");
459         uri_.append("stream://");
460     }
461     return ret;
462 }
463 
FindPlugin(const std::shared_ptr<MediaSource> & source)464 Status Source::FindPlugin(const std::shared_ptr<MediaSource>& source)
465 {
466     MediaAVCodec::AVCodecTrace trace("Source::FindPlugin");
467     if (!ParseProtocol(source)) {
468         MEDIA_LOG_E("Invalid source!");
469         return Status::ERROR_INVALID_PARAMETER;
470     }
471     if (protocol_.empty()) {
472         MEDIA_LOG_E("protocol_ is empty");
473         return Status::ERROR_INVALID_PARAMETER;
474     }
475     auto plugin = Plugins::PluginManagerV2::Instance().CreatePluginByMime(Plugins::PluginType::SOURCE, protocol_);
476     if (plugin != nullptr) {
477         plugin_ = std::static_pointer_cast<SourcePlugin>(plugin);
478         plugin_->SetInterruptState(isInterruptNeeded_);
479         return Status::OK;
480     }
481     MEDIA_LOG_E("Cannot find any plugin");
482     return Status::ERROR_UNSUPPORTED_FORMAT;
483 }
484 
GetDuration()485 int64_t Source::GetDuration()
486 {
487     FALSE_RETURN_V_MSG_W(seekToTimeFlag_, Plugins::HST_TIME_NONE, "Source GetDuration return -1 for isHls false");
488     FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Plugins::HST_TIME_NONE, "Source GetDuration error, plugin_ is nullptr");
489 
490     int64_t duration;
491     Status ret = plugin_->GetDuration(duration);
492     FALSE_RETURN_V_MSG_W(ret == Status::OK, Plugins::HST_TIME_NONE, "Source GetDuration from source plugin failed");
493     return duration;
494 }
495 
GetSize(uint64_t & fileSize)496 Status Source::GetSize(uint64_t &fileSize)
497 {
498     FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "GetSize Source plugin is nullptr!");
499     return plugin_->GetSize(fileSize);
500 }
501 
SelectStream(int32_t streamID)502 Status Source::SelectStream(int32_t streamID)
503 {
504     FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "SelectStream Source plugin is nullptr!");
505     return plugin_->SelectStream(streamID);
506 }
507 
GetSegmentOffset()508 size_t Source::GetSegmentOffset()
509 {
510     FALSE_RETURN_V_MSG_W(plugin_ != nullptr, 0, "GetSegmentOffset source pulgin is nullptr!");
511     return plugin_->GetSegmentOffset();
512 }
513 
GetHLSDiscontinuity()514 bool Source::GetHLSDiscontinuity()
515 {
516     FALSE_RETURN_V_MSG_W(plugin_ != nullptr, false, "GetHLSDiscontinuity source pulgin is nullptr!");
517     return plugin_->GetHLSDiscontinuity();
518 }
519 
SetEnableOnlineFdCache(bool isEnableFdCache)520 void Source::SetEnableOnlineFdCache(bool isEnableFdCache)
521 {
522     isEnableFdCache_ = isEnableFdCache;
523 }
524 
WaitForBufferingEnd()525 void Source::WaitForBufferingEnd()
526 {
527     FALSE_RETURN_MSG(plugin_ != nullptr, "WaitForBufferingEnd source plugin is nullptr");
528     return plugin_->WaitForBufferingEnd();
529 }
530 } // namespace Media
531 } // namespace OHOS
532