diff --git a/cobalt/dom/html_media_element.cc b/cobalt/dom/html_media_element.cc index 83f7311e5008..34f396f7d2bd 100644 --- a/cobalt/dom/html_media_element.cc +++ b/cobalt/dom/html_media_element.cc @@ -126,6 +126,27 @@ bool OriginIsSafe(loader::RequestMode request_mode, const GURL& resource_url, return false; } +const MediaSettings& GetMediaSettings( + const web::EnvironmentSettings* settings) { + DCHECK(settings); + DCHECK(settings->context()); + DCHECK(settings->context()->web_settings()); + + const auto& web_settings = settings->context()->web_settings(); + return web_settings->media_settings(); +} + +// If this function returns true, HTMLMediaElement::buffered() will attempt to +// call MediaSource::GetBufferedRange() if available, and fallback to +// WebMediaPlayer::UpdateBufferedTimeRanges(). +// The default value is false. +bool IsMediaElementUsingMediaSourceBufferedRangeEnabled( + const web::EnvironmentSettings* settings) { + return GetMediaSettings(settings) + .IsMediaElementUsingMediaSourceBufferedRangeEnabled() + .value_or(false); +} + } // namespace HTMLMediaElement::HTMLMediaElement(Document* document, @@ -218,6 +239,17 @@ uint16_t HTMLMediaElement::network_state() const { scoped_refptr HTMLMediaElement::buffered() const { scoped_refptr buffered = new TimeRanges; + DCHECK(node_document()); + DCHECK(node_document()->html_element_context()); + DCHECK(node_document()->html_element_context()->environment_settings()); + const auto* settings = + node_document()->html_element_context()->environment_settings(); + if (IsMediaElementUsingMediaSourceBufferedRangeEnabled(settings)) { + if (media_source_) { + return media_source_->GetBufferedRange(); + } + } + if (!player_) { LOG(INFO) << "(empty)"; return buffered; diff --git a/cobalt/dom/media_settings.cc b/cobalt/dom/media_settings.cc index ed39dbee25ed..2a9460d91485 100644 --- a/cobalt/dom/media_settings.cc +++ b/cobalt/dom/media_settings.cc @@ -83,6 +83,12 @@ bool MediaSettingsImpl::Set(const std::string& name, int value) { LOG(INFO) << name << ": set to " << value; return true; } + } else if (name == "MediaElement.EnableUsingMediaSourceBufferedRange") { + if (value == 0 || value == 1) { + is_media_element_using_media_source_buffered_range_enabled_ = value != 0; + LOG(INFO) << name << ": set to " << value; + return true; + } } else { LOG(WARNING) << "Ignore unknown setting with name \"" << name << "\""; return false; diff --git a/cobalt/dom/media_settings.h b/cobalt/dom/media_settings.h index 9f1a6f48798f..4f959e779a5d 100644 --- a/cobalt/dom/media_settings.h +++ b/cobalt/dom/media_settings.h @@ -42,6 +42,8 @@ class MediaSettings { virtual base::Optional GetMediaElementTimeupdateEventIntervalInMilliseconds() const = 0; virtual base::Optional IsPaintingVideoBackgroundToBlack() const = 0; + virtual base::Optional + IsMediaElementUsingMediaSourceBufferedRangeEnabled() const = 0; protected: MediaSettings() = default; @@ -93,6 +95,11 @@ class MediaSettingsImpl : public MediaSettings { base::Optional IsPaintingVideoBackgroundToBlack() const override { return is_painting_video_background_to_black_; } + base::Optional IsMediaElementUsingMediaSourceBufferedRangeEnabled() + const override { + base::AutoLock auto_lock(lock_); + return is_media_element_using_media_source_buffered_range_enabled_; + } // Returns true when the setting associated with `name` is set to `value`. // Returns false when `name` is not associated with any settings, or if @@ -110,6 +117,8 @@ class MediaSettingsImpl : public MediaSettings { base::Optional max_source_buffer_append_size_in_bytes_; base::Optional media_element_timeupdate_event_interval_in_milliseconds_; + base::Optional + is_media_element_using_media_source_buffered_range_enabled_; base::Optional is_painting_video_background_to_black_; }; diff --git a/cobalt/dom/media_settings_test.cc b/cobalt/dom/media_settings_test.cc index e4addfe40c23..6c462f3b66dd 100644 --- a/cobalt/dom/media_settings_test.cc +++ b/cobalt/dom/media_settings_test.cc @@ -48,6 +48,7 @@ TEST(MediaSettingsImplTest, SunnyDay) { ASSERT_TRUE( impl.Set("MediaElement.TimeupdateEventIntervalInMilliseconds", 100001)); ASSERT_TRUE(impl.Set("MediaElement.PaintingVideoBackgroundToBlack", 1)); + ASSERT_TRUE(impl.Set("MediaElement.EnableUsingMediaSourceBufferedRange", 1)); EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 100); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 101); @@ -59,6 +60,8 @@ TEST(MediaSettingsImplTest, SunnyDay) { EXPECT_EQ(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds().value(), 100001); EXPECT_TRUE(impl.IsPaintingVideoBackgroundToBlack().value()); + EXPECT_TRUE( + impl.IsMediaElementUsingMediaSourceBufferedRangeEnabled().value()); } TEST(MediaSettingsImplTest, RainyDay) { @@ -75,6 +78,8 @@ TEST(MediaSettingsImplTest, RainyDay) { ASSERT_FALSE( impl.Set("MediaElement.TimeupdateEventIntervalInMilliseconds", 0)); ASSERT_FALSE(impl.Set("MediaElement.PaintingVideoBackgroundToBlack", 2)); + ASSERT_FALSE( + impl.Set("MediaElement.EnableUsingMediaSourceBufferedRange", -101)); EXPECT_FALSE(impl.GetSourceBufferEvictExtraInBytes()); EXPECT_FALSE(impl.GetMinimumProcessorCountToOffloadAlgorithm()); @@ -85,6 +90,7 @@ TEST(MediaSettingsImplTest, RainyDay) { EXPECT_FALSE(impl.GetMaxSourceBufferAppendSizeInBytes()); EXPECT_FALSE(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds()); EXPECT_FALSE(impl.IsPaintingVideoBackgroundToBlack()); + EXPECT_FALSE(impl.IsMediaElementUsingMediaSourceBufferedRangeEnabled()); } TEST(MediaSettingsImplTest, ZeroValuesWork) { @@ -101,6 +107,7 @@ TEST(MediaSettingsImplTest, ZeroValuesWork) { // O is an invalid value for // "MediaElement.TimeupdateEventIntervalInMilliseconds". ASSERT_TRUE(impl.Set("MediaElement.PaintingVideoBackgroundToBlack", 0)); + ASSERT_TRUE(impl.Set("MediaElement.EnableUsingMediaSourceBufferedRange", 0)); EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 0); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 0); @@ -109,6 +116,8 @@ TEST(MediaSettingsImplTest, ZeroValuesWork) { EXPECT_FALSE(impl.IsCallingEndedWhenClosedEnabled().value()); EXPECT_EQ(impl.GetMaxSizeForImmediateJob().value(), 0); EXPECT_FALSE(impl.IsPaintingVideoBackgroundToBlack().value()); + EXPECT_FALSE( + impl.IsMediaElementUsingMediaSourceBufferedRangeEnabled().value()); } TEST(MediaSettingsImplTest, Updatable) { @@ -125,6 +134,7 @@ TEST(MediaSettingsImplTest, Updatable) { ASSERT_TRUE( impl.Set("MediaElement.TimeupdateEventIntervalInMilliseconds", 1)); ASSERT_TRUE(impl.Set("MediaElement.PaintingVideoBackgroundToBlack", 0)); + ASSERT_TRUE(impl.Set("MediaElement.EnableUsingMediaSourceBufferedRange", 0)); ASSERT_TRUE(impl.Set("MediaSource.SourceBufferEvictExtraInBytes", 1)); ASSERT_TRUE( @@ -137,6 +147,7 @@ TEST(MediaSettingsImplTest, Updatable) { ASSERT_TRUE( impl.Set("MediaElement.TimeupdateEventIntervalInMilliseconds", 2)); ASSERT_TRUE(impl.Set("MediaElement.PaintingVideoBackgroundToBlack", 1)); + ASSERT_TRUE(impl.Set("MediaElement.EnableUsingMediaSourceBufferedRange", 1)); EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 1); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 1); @@ -148,6 +159,8 @@ TEST(MediaSettingsImplTest, Updatable) { EXPECT_EQ(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds().value(), 2); EXPECT_TRUE(impl.IsPaintingVideoBackgroundToBlack().value()); + EXPECT_TRUE( + impl.IsMediaElementUsingMediaSourceBufferedRangeEnabled().value()); } TEST(MediaSettingsImplTest, InvalidSettingNames) { diff --git a/cobalt/dom/media_source.cc b/cobalt/dom/media_source.cc index f6edb8a8a74b..7312ad0e9d46 100644 --- a/cobalt/dom/media_source.cc +++ b/cobalt/dom/media_source.cc @@ -131,6 +131,18 @@ int GetMaxSizeForImmediateJob(web::EnvironmentSettings* settings) { return max_size; } +// If this function returns true, MediaSource::GetSeekable() will short-circuit +// getting the buffered range from HTMLMediaElement by directly calling to +// MediaSource::GetBufferedRange(). This reduces potential cross-object, +// cross-thread calls between MediaSource and HTMLMediaElement. +// The default value is false. +bool IsMediaElementUsingMediaSourceBufferedRangeEnabled( + web::EnvironmentSettings* settings) { + return GetMediaSettings(settings) + .IsMediaElementUsingMediaSourceBufferedRangeEnabled() + .value_or(false); +} + } // namespace MediaSource::MediaSource(script::EnvironmentSettings* settings) @@ -497,7 +509,13 @@ scoped_refptr MediaSource::GetSeekable() const { } if (source_duration == std::numeric_limits::infinity()) { - scoped_refptr buffered = attached_element_->buffered(); + scoped_refptr buffered = nullptr; + if (IsMediaElementUsingMediaSourceBufferedRangeEnabled( + environment_settings())) { + buffered = GetBufferedRange(); + } else { + buffered = attached_element_->buffered(); + } if (live_seekable_range_->length() != 0) { if (buffered->length() == 0) {