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) {