[MM][HBBTV] Enable the url demuxer for the hls video.
[platform/framework/web/chromium-efl.git] / media / filters / demuxer_manager.cc
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/filters/demuxer_manager.h"
6
7 #include "base/feature_list.h"
8 #include "base/functional/callback.h"
9 #include "base/metrics/histogram_functions.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_util.h"
12 #include "base/task/bind_post_task.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/task/task_runner.h"
15 #include "media/base/cross_origin_data_source.h"
16 #include "media/base/data_source.h"
17 #include "media/base/media_switches.h"
18 #include "media/base/media_url_demuxer.h"
19 #include "media/filters/chunk_demuxer.h"
20 #include "media/filters/ffmpeg_demuxer.h"
21 #include "url/gurl.h"
22
23 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
24 #include "media/filters/hls_manifest_demuxer_engine.h"
25 #include "media/filters/manifest_demuxer.h"
26 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER)
27
28 namespace media {
29
30 namespace {
31
32 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
33
34 // These values are persisted to logs. Entries should not be renumbered and
35 // numeric values should never be reused.
36 enum class MimeType {
37   kOtherMimeType = 0,
38   kApplicationDashXml = 1,
39   kApplicationOgg = 2,
40   kApplicationMpegUrl = 3,
41   kApplicationVndAppleMpegUrl = 4,
42   kApplicationXMpegUrl = 5,
43   kAudioMpegUrl = 6,
44   kAudioXMpegUrl = 7,
45   kNonspecificAudio = 8,
46   kNonspecificImage = 9,
47   kNonspecificVideo = 10,
48   kTextVtt = 11,
49   kMaxValue = kTextVtt,  // For UMA histograms.
50 };
51
52 MimeType TranslateMimeTypeToHistogramEnum(const base::StringPiece& mime_type) {
53   constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
54   if (base::StartsWith(mime_type, "application/dash+xml", kCaseInsensitive)) {
55     return MimeType::kApplicationDashXml;
56   }
57   if (base::StartsWith(mime_type, "application/ogg", kCaseInsensitive)) {
58     return MimeType::kApplicationOgg;
59   }
60   if (base::StartsWith(mime_type, "application/mpegurl", kCaseInsensitive)) {
61     return MimeType::kApplicationMpegUrl;
62   }
63   if (base::StartsWith(mime_type, "application/vnd.apple.mpegurl",
64                        kCaseInsensitive)) {
65     return MimeType::kApplicationVndAppleMpegUrl;
66   }
67   if (base::StartsWith(mime_type, "application/x-mpegurl", kCaseInsensitive)) {
68     return MimeType::kApplicationXMpegUrl;
69   }
70
71   if (base::StartsWith(mime_type, "audio/mpegurl", kCaseInsensitive)) {
72     return MimeType::kAudioMpegUrl;
73   }
74   if (base::StartsWith(mime_type, "audio/x-mpegurl", kCaseInsensitive)) {
75     return MimeType::kAudioXMpegUrl;
76   }
77
78   if (base::StartsWith(mime_type, "audio/", kCaseInsensitive)) {
79     return MimeType::kNonspecificAudio;
80   }
81   if (base::StartsWith(mime_type, "image/", kCaseInsensitive)) {
82     return MimeType::kNonspecificImage;
83   }
84   if (base::StartsWith(mime_type, "video/", kCaseInsensitive)) {
85     return MimeType::kNonspecificVideo;
86   }
87
88   if (base::StartsWith(mime_type, "text/vtt", kCaseInsensitive)) {
89     return MimeType::kTextVtt;
90   }
91
92   return MimeType::kOtherMimeType;
93 }
94
95 HlsFallbackImplementation SelectHlsFallbackImplementation() {
96 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
97   if (base::FeatureList::IsEnabled(kBuiltInHlsPlayer)) {
98     return HlsFallbackImplementation::kBuiltinHlsPlayer;
99   }
100 #endif
101
102 #if BUILDFLAG(IS_ANDROID)
103   if (base::FeatureList::IsEnabled(kHlsPlayer)) {
104     return HlsFallbackImplementation::kMediaPlayer;
105   }
106 #endif
107
108   return HlsFallbackImplementation::kNone;
109 }
110
111 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
112
113 #if BUILDFLAG(ENABLE_FFMPEG)
114 // Returns true if `url` represents (or is likely to) a local file.
115 bool IsLocalFile(const GURL& url) {
116   return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
117          url.SchemeIs(url::kContentScheme) ||
118          url.SchemeIs(url::kContentIDScheme) ||
119          url.SchemeIs("chrome-extension");
120 }
121 #endif
122
123 }  // namespace
124
125 DemuxerManager::DemuxerManager(
126     Client* client,
127     scoped_refptr<base::SequencedTaskRunner> media_task_runner,
128     MediaLog* log,
129     net::SiteForCookies site_for_cookies,
130     url::Origin top_frame_origin,
131     bool has_storage_access,
132     bool enable_instant_source_buffer_gc,
133     std::unique_ptr<Demuxer> demuxer_override)
134     : client_(client),
135       media_task_runner_(std::move(media_task_runner)),
136       media_log_(log->Clone()),
137       site_for_cookies_(std::move(site_for_cookies)),
138       top_frame_origin_(std::move(top_frame_origin)),
139 #if BUILDFLAG(IS_ANDROID)
140       has_storage_access_(has_storage_access),
141 #endif  // BUILDFLAG(IS_ANDROID)
142       enable_instant_source_buffer_gc_(enable_instant_source_buffer_gc),
143       demuxer_override_(std::move(demuxer_override)) {
144   DCHECK(client_);
145 }
146
147 DemuxerManager::~DemuxerManager() {
148   // ManifestDemuxer has multiple outstanding weak pointers bound to the media
149   // thread, and needs to be deleted there.
150   if (GetDemuxerType() == DemuxerType::kManifestDemuxer) {
151     media_task_runner_->DeleteSoon(FROM_HERE, std::move(demuxer_));
152   }
153 }
154
155 void DemuxerManager::InvalidateWeakPtrs() {
156   weak_factory_.InvalidateWeakPtrs();
157 }
158
159 void DemuxerManager::RestartClientForHLS() {
160   if (client_ && fallback_allowed_) {
161     client_->RestartForHls();
162   }
163 }
164
165 void DemuxerManager::OnPipelineError(PipelineStatus error) {
166   DCHECK(client_);
167
168   if (!fallback_allowed_) {
169     return client_->OnError(std::move(error));
170   }
171
172 #if defined(TIZEN_MULTIMEDIA)
173   if (error == DEMUXER_ERROR_DETECTED_HLS) {
174     hls_fallback_ = HlsFallbackImplementation::kMediaPlayer;
175
176     client_->StopForDemuxerReset();
177     data_source_->Stop();
178     FreeResourcesAfterMediaThreadWait(base::BindOnce(
179         &DemuxerManager::RestartClientForHLS, weak_factory_.GetWeakPtr()));
180
181     return;
182   }
183 #endif
184
185 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
186   bool can_play_hls =
187       SelectHlsFallbackImplementation() != HlsFallbackImplementation::kNone;
188   if (can_play_hls && error == DEMUXER_ERROR_DETECTED_HLS) {
189     PipelineStatus reset_status =
190         SelectHlsFallbackMechanism(client_->IsSecurityOriginCryptographic());
191     if (!reset_status.is_ok()) {
192       client_->OnError(std::move(reset_status).AddCause(std::move(error)));
193       return;
194     }
195
196     // The data source must be stopped after the client, after which the
197     // old demuxer and data source can be freed.
198     client_->StopForDemuxerReset();
199     data_source_->Stop();
200     FreeResourcesAfterMediaThreadWait(base::BindOnce(
201         &DemuxerManager::RestartClientForHLS, weak_factory_.GetWeakPtr()));
202
203     return;
204   }
205 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
206
207   client_->OnError(std::move(error));
208 }
209
210 void DemuxerManager::FreeResourcesAfterMediaThreadWait(base::OnceClosure cb) {
211   // The demuxer and data source must be freed on the main thread, but we have
212   // to make sure nothing is using them on the media thread first. So we have
213   // to post to the media thread and back.
214   media_task_runner_->PostTask(
215       FROM_HERE,
216       base::BindPostTaskToCurrentDefault(base::BindOnce(
217           [](std::unique_ptr<Demuxer> demuxer,
218              std::unique_ptr<DataSource> data_source,
219              base::OnceClosure done_cb) {
220             demuxer.reset();
221             data_source.reset();
222             std::move(done_cb).Run();
223           },
224           std::move(demuxer_), std::move(data_source_), std::move(cb))));
225 }
226
227 void DemuxerManager::DisallowFallback() {
228   fallback_allowed_ = false;
229 }
230
231 void DemuxerManager::SetLoadedUrl(GURL url) {
232   // The URL might be a rather large data:// url, so move it to prevent a
233   // copy.
234   loaded_url_ = std::move(url);
235 }
236
237 const GURL& DemuxerManager::LoadedUrl() const {
238   return loaded_url_;
239 }
240
241 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
242
243 void DemuxerManager::PopulateHlsHistograms(bool cryptographic_url) {
244   DCHECK(data_source_);
245
246   if (auto* co_data_source = data_source_->GetAsCrossOriginDataSource()) {
247     MimeType mime_type =
248         TranslateMimeTypeToHistogramEnum(co_data_source->GetMimeType());
249     base::UmaHistogramEnumeration("Media.WebMediaPlayerImpl.HLS.MimeType",
250                                   mime_type);
251
252     bool is_cross_origin = co_data_source->IsCorsCrossOrigin();
253     UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
254                           is_cross_origin);
255     if (is_cross_origin) {
256       UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl",
257                             co_data_source->HasAccessControl());
258       base::UmaHistogramEnumeration(
259           "Media.WebMediaPlayerImpl.HLS.CorsCrossOrigin.MimeType", mime_type);
260     }
261   } else {
262     UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
263                           false);
264   }
265
266   bool is_mixed_content =
267       cryptographic_url &&
268       (!loaded_url_.SchemeIsCryptographic() ||
269        GetDataSourceUrlAfterRedirects()->SchemeIsCryptographic());
270   UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsMixedContent",
271                         is_mixed_content);
272 }
273
274 PipelineStatus DemuxerManager::SelectHlsFallbackMechanism(
275     bool cryptographic_url) {
276   hls_fallback_ = SelectHlsFallbackImplementation();
277   if (hls_fallback_ == HlsFallbackImplementation::kNone) {
278     return DEMUXER_ERROR_DETECTED_HLS;
279   }
280
281   // If we've gotten a request to start HLS fallback and logging, we can assert
282   // that data source has been set.
283   CHECK(data_source_);
284
285   // |data_source_| might be a MemoryDataSource if our URL is a data:// url.
286   // Since MediaPlayer doesn't support this type of URL, we can't fall back to
287   // android's HLS implementation. Since HLS is enabled, we should report a
288   // failed external renderer, since we know MediaPlayerRenderer would fail
289   // anyway here.
290   bool is_mp = hls_fallback_ == HlsFallbackImplementation::kMediaPlayer;
291   if (!data_source_->GetAsCrossOriginDataSource() && is_mp) {
292     // Media player requires that the data source not be a data:// url.
293     return PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
294   }
295
296   loaded_url_ = GetDataSourceUrlAfterRedirects().value();
297
298   // We do not support using blob and filesystem schemes with the Android
299   // MediaPlayer. Fail now rather than during MediaPlayerRender initialization.
300   if (is_mp &&
301       (loaded_url_.SchemeIsBlob() || loaded_url_.SchemeIsFileSystem())) {
302     return PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
303   }
304
305   PopulateHlsHistograms(cryptographic_url);
306
307   if (client_) {
308     client_->UpdateLoadedUrl(loaded_url_);
309   }
310
311   return OkStatus();
312 }
313
314 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
315
316 absl::optional<double> DemuxerManager::GetDemuxerDuration() {
317   if (!demuxer_) {
318     return absl::nullopt;
319   }
320   if (demuxer_->GetDemuxerType() != DemuxerType::kChunkDemuxer) {
321     return absl::nullopt;
322   }
323
324   // Use duration from ChunkDemuxer when present. MSE allows users to specify
325   // duration as a double. This propagates to the rest of the pipeline as a
326   // TimeDelta with potentially reduced precision (limited to Microseconds).
327   // ChunkDemuxer returns the full-precision user-specified double. This ensures
328   // users can "get" the exact duration they "set".
329   // TODO(crbug/1377053) Get rid of this static cast.
330   return static_cast<ChunkDemuxer*>(demuxer_.get())->GetDuration();
331 }
332
333 absl::optional<DemuxerType> DemuxerManager::GetDemuxerType() const {
334   if (!demuxer_) {
335     return absl::nullopt;
336   }
337   return demuxer_->GetDemuxerType();
338 }
339
340 absl::optional<container_names::MediaContainerName>
341 DemuxerManager::GetContainerForMetrics() {
342   if (!demuxer_) {
343     return absl::nullopt;
344   }
345   return demuxer_->GetContainerForMetrics();
346 }
347
348 void DemuxerManager::RespondToDemuxerMemoryUsageReport(
349     base::OnceCallback<void(int64_t)> cb) {
350   if (!demuxer_) {
351     return std::move(cb).Run(0);
352   }
353   switch (demuxer_->GetDemuxerType()) {
354     case DemuxerType::kChunkDemuxer:
355       // ChunkDemuxer locks while getting the memory size, so we don't have
356       // to post cross thread.
357       return std::move(cb).Run(demuxer_->GetMemoryUsage());
358     case DemuxerType::kMediaUrlDemuxer:
359       // MediaUrlDemuxer always returns a constant.
360       return std::move(cb).Run(demuxer_->GetMemoryUsage());
361     default:
362       // FFmpegDemuxer is single threaded and only runs on the media thread,
363       // so we have to post there and wait for the reply. We can't be sure what
364       // other demuxers do.
365       // base::Unretained is safe here because |this| is posted for destruction
366       // and |this| strongly owns |demuxer_|. See WMPI::ReportMemoryUsage() for
367       // more information about destruction order.
368       media_task_runner_->PostTaskAndReplyWithResult(
369           FROM_HERE,
370           base::BindOnce(&Demuxer::GetMemoryUsage,
371                          base::Unretained(demuxer_.get())),
372           std::move(cb));
373       break;
374   }
375 }
376
377 void DemuxerManager::DisableDemuxerCanChangeType() {
378   demuxer_->DisableCanChangeType();
379 }
380
381 PipelineStatus DemuxerManager::CreateDemuxer(
382     bool load_media_source,
383     DataSource::Preload preload,
384     bool needs_first_frame,
385     DemuxerManager::DemuxerCreatedCB on_demuxer_created) {
386   // TODO(crbug/1377053) return a better error
387   if (!client_) {
388     return DEMUXER_ERROR_COULD_NOT_OPEN;
389   }
390
391   // We can only do a universal suspend for posters, unless the flag is enabled.
392   auto suspended_mode = Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
393   if (!needs_first_frame) {
394     suspended_mode = Pipeline::StartType::kSuspendAfterMetadata;
395   }
396
397 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
398   if (hls_fallback_ == HlsFallbackImplementation::kBuiltinHlsPlayer ||
399       (base::FeatureList::IsEnabled(kBuiltInHlsPlayer) &&
400        loaded_url_.path_piece().ends_with(".m3u8"))) {
401     SetDemuxer(CreateHlsDemuxer());
402     return std::move(on_demuxer_created)
403         .Run(demuxer_.get(), suspended_mode, /*is_streaming=*/false,
404              /*is_static=*/false);
405   }
406 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER)
407
408 #if BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA)
409   const bool media_player_hls =
410       hls_fallback_ == HlsFallbackImplementation::kMediaPlayer;
411   if (media_player_hls || client_->IsMediaPlayerRendererClient()) {
412     SetDemuxer(CreateMediaUrlDemuxer(media_player_hls));
413     return std::move(on_demuxer_created)
414         .Run(demuxer_.get(), Pipeline::StartType::kNormal,
415              /*is_streaming = */ false,
416              /*is_static = */ false);
417   }
418 #endif
419
420   // TODO(sandersd): FileSystem objects may also be non-static, but due to our
421   // caching layer such situations are broken already. http://crbug.com/593159
422   bool is_static = true;
423
424   if (demuxer_override_) {
425     // TODO(https://crbug.com/1076267): Should everything else after this block
426     // run in the demuxer override case?
427     SetDemuxer(std::move(demuxer_override_));
428   } else if (!load_media_source) {
429 #if BUILDFLAG(ENABLE_FFMPEG)
430     SetDemuxer(CreateFFmpegDemuxer());
431 #else
432     return DEMUXER_ERROR_COULD_NOT_OPEN;
433 #endif
434   } else {
435     DCHECK(!HasDataSource());
436     SetDemuxer(CreateChunkDemuxer());
437     is_static = false;
438   }
439
440   if (!demuxer_) {
441     return DEMUXER_ERROR_COULD_NOT_OPEN;
442   }
443
444   // A myriad of reasons exists that prevent us from entering a suspended state
445   // after metadata is reached - in this case we'll have to do a normal startup.
446   if (demuxer_->GetDemuxerType() == DemuxerType::kChunkDemuxer ||
447       preload != DataSource::METADATA || client_->CouldPlayIfEnoughData() ||
448       IsStreaming()) {
449     return std::move(on_demuxer_created)
450         .Run(demuxer_.get(), Pipeline::StartType::kNormal, IsStreaming(),
451              is_static);
452   }
453
454   return std::move(on_demuxer_created)
455       .Run(demuxer_.get(), suspended_mode, IsStreaming(), is_static);
456 }
457
458 #if BUILDFLAG(IS_ANDROID)
459 void DemuxerManager::SetAllowMediaPlayerRendererCredentials(bool allow) {
460   allow_media_player_renderer_credentials_ = allow;
461 }
462 #endif  // BUILDFLAG(IS_ANDROID)
463
464 const DataSource* DemuxerManager::GetDataSourceForTesting() const {
465   return data_source_.get();
466 }
467
468 void DemuxerManager::SetDataSource(std::unique_ptr<DataSource> data_source) {
469   data_source_ = std::move(data_source);
470 }
471
472 void DemuxerManager::OnBufferingHaveEnough(bool enough) {
473   CHECK(data_source_);
474   data_source_->OnBufferingHaveEnough(enough);
475 }
476
477 void DemuxerManager::SetPreload(DataSource::Preload preload) {
478   if (data_source_) {
479     data_source_->SetPreload(preload);
480   }
481 }
482
483 void DemuxerManager::StopAndResetClient(Client* client) {
484   if (data_source_) {
485     data_source_->Stop();
486   }
487   client_ = client;
488 }
489
490 int64_t DemuxerManager::GetDataSourceMemoryUsage() {
491   return data_source_ ? data_source_->GetMemoryUsage() : 0;
492 }
493
494 void DemuxerManager::OnDataSourcePlaybackRateChange(double rate, bool paused) {
495   if (!data_source_) {
496     return;
497   }
498   data_source_->OnMediaPlaybackRateChanged(rate);
499   if (!paused) {
500     data_source_->OnMediaIsPlaying();
501   }
502 }
503
504 bool DemuxerManager::WouldTaintOrigin() const {
505   if (hls_fallback_ != HlsFallbackImplementation::kNone) {
506     // HLS manifests might pull segments from a different origin. We can't know
507     // for sure, so we conservatively say yes here.
508     // TODO (crbug/1266991) We will be able to know for sure with the builtin
509     // player, when that's implemented.
510     return true;
511   }
512
513   // TODO(crbug/1377053): The default |false| value might have to be
514   // re-considered for MediaPlayerRenderer, but for now, leave behavior the
515   // same as it was.
516   return data_source_ ? data_source_->WouldTaintOrigin() : false;
517 }
518
519 bool DemuxerManager::HasDataSource() const {
520   return data_source_ != nullptr;
521 }
522
523 bool DemuxerManager::HasDemuxer() const {
524   return !!demuxer_;
525 }
526
527 bool DemuxerManager::HasDemuxerOverride() const {
528   return !!demuxer_override_;
529 }
530
531 absl::optional<GURL> DemuxerManager::GetDataSourceUrlAfterRedirects() const {
532   if (data_source_) {
533     return data_source_->GetUrlAfterRedirects();
534   }
535   return absl::nullopt;
536 }
537
538 bool DemuxerManager::DataSourceFullyBuffered() const {
539   return data_source_ && data_source_->AssumeFullyBuffered();
540 }
541
542 bool DemuxerManager::IsStreaming() const {
543   return (data_source_ && data_source_->IsStreaming()) ||
544          (demuxer_ && !demuxer_->IsSeekable());
545 }
546
547 bool DemuxerManager::PassedDataSourceTimingAllowOriginCheck() const {
548   // If there is no MultiBuffer, then there are no HTTP responses, and so this
549   // can safely return true. Specifically for the MSE case, the app itself
550   // sources the ArrayBuffer[Views], possibly not even from HTTP responses. Any
551   // TAO checks which are present to prevent deduction of the resource content
552   // can be assumed to have passed, as the content is already readable by the
553   // app. TAO checks which would be used to determine other network timing
554   // info, such as DNS lookup time, are not relevant as the media data is far
555   // removed from the network itself at this point, and so that info cannot be
556   // revealed via the MediaSource or WebMediaPlayer that's using MSE.
557   // TODO(1266991): Ensure that this returns the correct value for HLS media,
558   // based on the TAO checks performed on those resources.
559   return data_source_ ? data_source_->PassedTimingAllowOriginCheck() : true;
560 }
561
562 bool DemuxerManager::IsLiveContent() const {
563   // Manifest demuxer reports true live content accurately, while all other
564   // demuxers do not. TODO(crbug/1266991): Consider making IsSeekable return
565   // an enum class with vod/semi-live/true-live states.
566   if (GetDemuxerType() == DemuxerType::kManifestDemuxer) {
567     return !demuxer_->IsSeekable();
568   }
569   return false;
570 }
571
572 std::unique_ptr<Demuxer> DemuxerManager::CreateChunkDemuxer() {
573   if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
574     memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
575         FROM_HERE, base::BindRepeating(&DemuxerManager::OnMemoryPressure,
576                                        base::Unretained(this)));
577   }
578
579   return std::make_unique<ChunkDemuxer>(
580       base::BindPostTaskToCurrentDefault(base::BindOnce(
581           &DemuxerManager::OnChunkDemuxerOpened, weak_factory_.GetWeakPtr())),
582       base::BindPostTaskToCurrentDefault(base::BindRepeating(
583           &DemuxerManager::OnProgress, weak_factory_.GetWeakPtr())),
584       base::BindPostTaskToCurrentDefault(
585           base::BindRepeating(&DemuxerManager::OnEncryptedMediaInitData,
586                               weak_factory_.GetWeakPtr())),
587       media_log_.get());
588 }
589
590 #if BUILDFLAG(ENABLE_FFMPEG)
591 std::unique_ptr<Demuxer> DemuxerManager::CreateFFmpegDemuxer() {
592   DCHECK(data_source_);
593   return std::make_unique<FFmpegDemuxer>(
594       media_task_runner_, data_source_.get(),
595       base::BindPostTaskToCurrentDefault(
596           base::BindRepeating(&DemuxerManager::OnEncryptedMediaInitData,
597                               weak_factory_.GetWeakPtr())),
598       base::BindPostTaskToCurrentDefault(
599           base::BindRepeating(&DemuxerManager::OnFFmpegMediaTracksUpdated,
600                               weak_factory_.GetWeakPtr())),
601       media_log_.get(), IsLocalFile(loaded_url_));
602 }
603 #endif  // BUILDFLAG(ENABLE_FFMPEG)
604
605 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
606 std::unique_ptr<Demuxer> DemuxerManager::CreateHlsDemuxer() {
607   auto engine = std::make_unique<HlsManifestDemuxerEngine>(
608       client_->GetHlsDataSourceProvider(), media_task_runner_, loaded_url_,
609       media_log_.get());
610   return std::make_unique<ManifestDemuxer>(
611       media_task_runner_,
612       base::BindPostTaskToCurrentDefault(base::BindRepeating(
613           &DemuxerManager::DemuxerRequestsSeek, weak_factory_.GetWeakPtr())),
614       std::move(engine), media_log_.get());
615 }
616 #endif
617
618 #if BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA)
619 std::unique_ptr<Demuxer> DemuxerManager::CreateMediaUrlDemuxer(
620     bool expect_hls_content) {
621   return std::make_unique<MediaUrlDemuxer>(
622       media_task_runner_, loaded_url_, site_for_cookies_, top_frame_origin_,
623 #if BUILDFLAG(IS_ANDROID)
624       has_storage_access_, allow_media_player_renderer_credentials_,
625 #else
626       // The platform media player in Tizen OS doesn't require these params
627       // except for the url, so they are not used for tizen multimedia.
628       true, true,
629 #endif
630       expect_hls_content);
631 }
632 #endif  // BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA)
633
634 void DemuxerManager::SetDemuxer(std::unique_ptr<Demuxer> demuxer) {
635   DCHECK(!demuxer_);
636   CHECK(demuxer);
637
638   demuxer_ = std::move(demuxer);
639   if (client_) {
640     client_->MakeDemuxerThreadDumper(demuxer_.get());
641   }
642 }
643
644 void DemuxerManager::OnEncryptedMediaInitData(
645     EmeInitDataType init_data_type,
646     const std::vector<uint8_t>& init_data) {
647   if (client_) {
648     client_->OnEncryptedMediaInitData(init_data_type, init_data);
649   }
650 }
651
652 void DemuxerManager::OnMemoryPressure(
653     base::MemoryPressureListener::MemoryPressureLevel level) {
654   DVLOG(2) << __func__ << " level=" << level;
655   DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
656   DCHECK(GetDemuxerType() == DemuxerType::kChunkDemuxer);
657
658   if (level == base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
659     return;
660   }
661
662   // The new value of `level` will take effect on the next
663   // garbage collection. Typically this means the next SourceBuffer append()
664   // operation, since per MSE spec, the garbage collection must only occur
665   // during SourceBuffer append(). But if memory pressure is critical it might
666   // be better to perform GC immediately rather than wait for the next append
667   // and potentially get killed due to out-of-memory.
668   // So if this experiment is enabled and pressure level is critical, we'll pass
669   // down force_instant_gc==true, which will force immediate GC on
670   // SourceBufferStreams.
671   bool force_instant_gc =
672       (enable_instant_source_buffer_gc_ &&
673        level == base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
674
675   if (!client_) {
676     return;
677   }
678
679   // base::Unretained is safe, since `demuxer_` is actually owned by
680   // `this` via this->demuxer_. Note the destruction of `demuxer_` is done
681   // from ~WMPI by first hopping to `media_task_runner_` to prevent race with
682   // this task.
683   // TODO(crbug/1377053) Get rid of this static cast.
684   media_task_runner_->PostTask(
685       FROM_HERE,
686       base::BindOnce(
687           &ChunkDemuxer::OnMemoryPressure,
688           base::Unretained(static_cast<ChunkDemuxer*>(demuxer_.get())),
689           base::Seconds(client_->CurrentTime()), level, force_instant_gc));
690 }
691
692 void DemuxerManager::OnChunkDemuxerOpened() {
693   CHECK(demuxer_);
694   CHECK(demuxer_->GetDemuxerType() == DemuxerType::kChunkDemuxer);
695   // TODO(crbug/1377053) Get rid of this static cast.
696   if (client_) {
697     client_->OnChunkDemuxerOpened(static_cast<ChunkDemuxer*>(demuxer_.get()));
698   }
699 }
700
701 void DemuxerManager::OnProgress() {
702   if (client_) {
703     client_->OnProgress();
704   }
705 }
706
707 #if BUILDFLAG(ENABLE_FFMPEG)
708 void DemuxerManager::OnFFmpegMediaTracksUpdated(
709     std::unique_ptr<MediaTracks> tracks) {
710   DCHECK(demuxer_);
711
712   // For MSE/chunk_demuxer case the media track updates are handled by
713   // WebSourceBufferImpl.
714   DCHECK(GetDemuxerType() != DemuxerType::kChunkDemuxer);
715
716   // we might be in the process of being destroyed when this happens.
717   if (!client_) {
718     return;
719   }
720
721   // Only the first audio track and the first video track are enabled by
722   // default to match blink logic.
723   bool is_first_audio_track = true;
724   bool is_first_video_track = true;
725   for (const auto& track : tracks->tracks()) {
726     if (track->type() == MediaTrack::Type::kAudio) {
727       client_->AddAudioTrack(track->id().value(), track->label().value(),
728                              track->language().value(), is_first_audio_track);
729       is_first_audio_track = false;
730     } else if (track->type() == MediaTrack::Type::kVideo) {
731       client_->AddVideoTrack(track->id().value(), track->label().value(),
732                              track->language().value(), is_first_video_track);
733       is_first_video_track = false;
734     } else {
735       // Text tracks are not supported through this code path.
736       NOTREACHED();
737     }
738   }
739 }
740 #endif  // BUILDFLAG(ENABLE_FFMPEG)
741
742 void DemuxerManager::DemuxerRequestsSeek(base::TimeDelta time) {
743   if (!client_) {
744     return;
745   }
746   client_->DemuxerRequestsSeek(time);
747 }
748
749 }  // namespace media