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.
5 #include "media/filters/demuxer_manager.h"
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"
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)
32 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
34 // These values are persisted to logs. Entries should not be renumbered and
35 // numeric values should never be reused.
38 kApplicationDashXml = 1,
40 kApplicationMpegUrl = 3,
41 kApplicationVndAppleMpegUrl = 4,
42 kApplicationXMpegUrl = 5,
45 kNonspecificAudio = 8,
46 kNonspecificImage = 9,
47 kNonspecificVideo = 10,
49 kMaxValue = kTextVtt, // For UMA histograms.
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;
57 if (base::StartsWith(mime_type, "application/ogg", kCaseInsensitive)) {
58 return MimeType::kApplicationOgg;
60 if (base::StartsWith(mime_type, "application/mpegurl", kCaseInsensitive)) {
61 return MimeType::kApplicationMpegUrl;
63 if (base::StartsWith(mime_type, "application/vnd.apple.mpegurl",
65 return MimeType::kApplicationVndAppleMpegUrl;
67 if (base::StartsWith(mime_type, "application/x-mpegurl", kCaseInsensitive)) {
68 return MimeType::kApplicationXMpegUrl;
71 if (base::StartsWith(mime_type, "audio/mpegurl", kCaseInsensitive)) {
72 return MimeType::kAudioMpegUrl;
74 if (base::StartsWith(mime_type, "audio/x-mpegurl", kCaseInsensitive)) {
75 return MimeType::kAudioXMpegUrl;
78 if (base::StartsWith(mime_type, "audio/", kCaseInsensitive)) {
79 return MimeType::kNonspecificAudio;
81 if (base::StartsWith(mime_type, "image/", kCaseInsensitive)) {
82 return MimeType::kNonspecificImage;
84 if (base::StartsWith(mime_type, "video/", kCaseInsensitive)) {
85 return MimeType::kNonspecificVideo;
88 if (base::StartsWith(mime_type, "text/vtt", kCaseInsensitive)) {
89 return MimeType::kTextVtt;
92 return MimeType::kOtherMimeType;
95 HlsFallbackImplementation SelectHlsFallbackImplementation() {
96 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
97 if (base::FeatureList::IsEnabled(kBuiltInHlsPlayer)) {
98 return HlsFallbackImplementation::kBuiltinHlsPlayer;
102 #if BUILDFLAG(IS_ANDROID)
103 if (base::FeatureList::IsEnabled(kHlsPlayer)) {
104 return HlsFallbackImplementation::kMediaPlayer;
108 return HlsFallbackImplementation::kNone;
111 #endif // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
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");
125 DemuxerManager::DemuxerManager(
127 scoped_refptr<base::SequencedTaskRunner> media_task_runner,
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)
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)) {
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_));
155 void DemuxerManager::InvalidateWeakPtrs() {
156 weak_factory_.InvalidateWeakPtrs();
159 void DemuxerManager::RestartClientForHLS() {
160 if (client_ && fallback_allowed_) {
161 client_->RestartForHls();
165 void DemuxerManager::OnPipelineError(PipelineStatus error) {
168 if (!fallback_allowed_) {
169 return client_->OnError(std::move(error));
172 #if defined(TIZEN_MULTIMEDIA)
173 if (error == DEMUXER_ERROR_DETECTED_HLS) {
174 hls_fallback_ = HlsFallbackImplementation::kMediaPlayer;
176 client_->StopForDemuxerReset();
177 data_source_->Stop();
178 FreeResourcesAfterMediaThreadWait(base::BindOnce(
179 &DemuxerManager::RestartClientForHLS, weak_factory_.GetWeakPtr()));
185 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
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)));
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()));
205 #endif // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
207 client_->OnError(std::move(error));
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(
216 base::BindPostTaskToCurrentDefault(base::BindOnce(
217 [](std::unique_ptr<Demuxer> demuxer,
218 std::unique_ptr<DataSource> data_source,
219 base::OnceClosure done_cb) {
222 std::move(done_cb).Run();
224 std::move(demuxer_), std::move(data_source_), std::move(cb))));
227 void DemuxerManager::DisallowFallback() {
228 fallback_allowed_ = false;
231 void DemuxerManager::SetLoadedUrl(GURL url) {
232 // The URL might be a rather large data:// url, so move it to prevent a
234 loaded_url_ = std::move(url);
237 const GURL& DemuxerManager::LoadedUrl() const {
241 #if BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
243 void DemuxerManager::PopulateHlsHistograms(bool cryptographic_url) {
244 DCHECK(data_source_);
246 if (auto* co_data_source = data_source_->GetAsCrossOriginDataSource()) {
248 TranslateMimeTypeToHistogramEnum(co_data_source->GetMimeType());
249 base::UmaHistogramEnumeration("Media.WebMediaPlayerImpl.HLS.MimeType",
252 bool is_cross_origin = co_data_source->IsCorsCrossOrigin();
253 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
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);
262 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
266 bool is_mixed_content =
268 (!loaded_url_.SchemeIsCryptographic() ||
269 GetDataSourceUrlAfterRedirects()->SchemeIsCryptographic());
270 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsMixedContent",
274 PipelineStatus DemuxerManager::SelectHlsFallbackMechanism(
275 bool cryptographic_url) {
276 hls_fallback_ = SelectHlsFallbackImplementation();
277 if (hls_fallback_ == HlsFallbackImplementation::kNone) {
278 return DEMUXER_ERROR_DETECTED_HLS;
281 // If we've gotten a request to start HLS fallback and logging, we can assert
282 // that data source has been set.
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
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;
296 loaded_url_ = GetDataSourceUrlAfterRedirects().value();
298 // We do not support using blob and filesystem schemes with the Android
299 // MediaPlayer. Fail now rather than during MediaPlayerRender initialization.
301 (loaded_url_.SchemeIsBlob() || loaded_url_.SchemeIsFileSystem())) {
302 return PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
305 PopulateHlsHistograms(cryptographic_url);
308 client_->UpdateLoadedUrl(loaded_url_);
314 #endif // BUILDFLAG(ENABLE_HLS_DEMUXER) || BUILDFLAG(IS_ANDROID)
316 absl::optional<double> DemuxerManager::GetDemuxerDuration() {
318 return absl::nullopt;
320 if (demuxer_->GetDemuxerType() != DemuxerType::kChunkDemuxer) {
321 return absl::nullopt;
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();
333 absl::optional<DemuxerType> DemuxerManager::GetDemuxerType() const {
335 return absl::nullopt;
337 return demuxer_->GetDemuxerType();
340 absl::optional<container_names::MediaContainerName>
341 DemuxerManager::GetContainerForMetrics() {
343 return absl::nullopt;
345 return demuxer_->GetContainerForMetrics();
348 void DemuxerManager::RespondToDemuxerMemoryUsageReport(
349 base::OnceCallback<void(int64_t)> cb) {
351 return std::move(cb).Run(0);
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());
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(
370 base::BindOnce(&Demuxer::GetMemoryUsage,
371 base::Unretained(demuxer_.get())),
377 void DemuxerManager::DisableDemuxerCanChangeType() {
378 demuxer_->DisableCanChangeType();
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
388 return DEMUXER_ERROR_COULD_NOT_OPEN;
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;
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);
406 #endif // BUILDFLAG(ENABLE_HLS_DEMUXER)
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);
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;
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());
432 return DEMUXER_ERROR_COULD_NOT_OPEN;
435 DCHECK(!HasDataSource());
436 SetDemuxer(CreateChunkDemuxer());
441 return DEMUXER_ERROR_COULD_NOT_OPEN;
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() ||
449 return std::move(on_demuxer_created)
450 .Run(demuxer_.get(), Pipeline::StartType::kNormal, IsStreaming(),
454 return std::move(on_demuxer_created)
455 .Run(demuxer_.get(), suspended_mode, IsStreaming(), is_static);
458 #if BUILDFLAG(IS_ANDROID)
459 void DemuxerManager::SetAllowMediaPlayerRendererCredentials(bool allow) {
460 allow_media_player_renderer_credentials_ = allow;
462 #endif // BUILDFLAG(IS_ANDROID)
464 const DataSource* DemuxerManager::GetDataSourceForTesting() const {
465 return data_source_.get();
468 void DemuxerManager::SetDataSource(std::unique_ptr<DataSource> data_source) {
469 data_source_ = std::move(data_source);
472 void DemuxerManager::OnBufferingHaveEnough(bool enough) {
474 data_source_->OnBufferingHaveEnough(enough);
477 void DemuxerManager::SetPreload(DataSource::Preload preload) {
479 data_source_->SetPreload(preload);
483 void DemuxerManager::StopAndResetClient(Client* client) {
485 data_source_->Stop();
490 int64_t DemuxerManager::GetDataSourceMemoryUsage() {
491 return data_source_ ? data_source_->GetMemoryUsage() : 0;
494 void DemuxerManager::OnDataSourcePlaybackRateChange(double rate, bool paused) {
498 data_source_->OnMediaPlaybackRateChanged(rate);
500 data_source_->OnMediaIsPlaying();
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.
513 // TODO(crbug/1377053): The default |false| value might have to be
514 // re-considered for MediaPlayerRenderer, but for now, leave behavior the
516 return data_source_ ? data_source_->WouldTaintOrigin() : false;
519 bool DemuxerManager::HasDataSource() const {
520 return data_source_ != nullptr;
523 bool DemuxerManager::HasDemuxer() const {
527 bool DemuxerManager::HasDemuxerOverride() const {
528 return !!demuxer_override_;
531 absl::optional<GURL> DemuxerManager::GetDataSourceUrlAfterRedirects() const {
533 return data_source_->GetUrlAfterRedirects();
535 return absl::nullopt;
538 bool DemuxerManager::DataSourceFullyBuffered() const {
539 return data_source_ && data_source_->AssumeFullyBuffered();
542 bool DemuxerManager::IsStreaming() const {
543 return (data_source_ && data_source_->IsStreaming()) ||
544 (demuxer_ && !demuxer_->IsSeekable());
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;
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();
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)));
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())),
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_));
603 #endif // BUILDFLAG(ENABLE_FFMPEG)
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_,
610 return std::make_unique<ManifestDemuxer>(
612 base::BindPostTaskToCurrentDefault(base::BindRepeating(
613 &DemuxerManager::DemuxerRequestsSeek, weak_factory_.GetWeakPtr())),
614 std::move(engine), media_log_.get());
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_,
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.
632 #endif // BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA)
634 void DemuxerManager::SetDemuxer(std::unique_ptr<Demuxer> demuxer) {
638 demuxer_ = std::move(demuxer);
640 client_->MakeDemuxerThreadDumper(demuxer_.get());
644 void DemuxerManager::OnEncryptedMediaInitData(
645 EmeInitDataType init_data_type,
646 const std::vector<uint8_t>& init_data) {
648 client_->OnEncryptedMediaInitData(init_data_type, init_data);
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);
658 if (level == base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
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);
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
683 // TODO(crbug/1377053) Get rid of this static cast.
684 media_task_runner_->PostTask(
687 &ChunkDemuxer::OnMemoryPressure,
688 base::Unretained(static_cast<ChunkDemuxer*>(demuxer_.get())),
689 base::Seconds(client_->CurrentTime()), level, force_instant_gc));
692 void DemuxerManager::OnChunkDemuxerOpened() {
694 CHECK(demuxer_->GetDemuxerType() == DemuxerType::kChunkDemuxer);
695 // TODO(crbug/1377053) Get rid of this static cast.
697 client_->OnChunkDemuxerOpened(static_cast<ChunkDemuxer*>(demuxer_.get()));
701 void DemuxerManager::OnProgress() {
703 client_->OnProgress();
707 #if BUILDFLAG(ENABLE_FFMPEG)
708 void DemuxerManager::OnFFmpegMediaTracksUpdated(
709 std::unique_ptr<MediaTracks> tracks) {
712 // For MSE/chunk_demuxer case the media track updates are handled by
713 // WebSourceBufferImpl.
714 DCHECK(GetDemuxerType() != DemuxerType::kChunkDemuxer);
716 // we might be in the process of being destroyed when this happens.
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;
735 // Text tracks are not supported through this code path.
740 #endif // BUILDFLAG(ENABLE_FFMPEG)
742 void DemuxerManager::DemuxerRequestsSeek(base::TimeDelta time) {
746 client_->DemuxerRequestsSeek(time);