Adds use of SurfaceLayerBridge into WebMediaPlayerMS.

This CL allows for WebMediaPlayerMS to create a SurfaceLayerBridge and
interface with it in order to use a Surface for video playback.

Bug: 746182
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I39174499a7e659eeeef13a81f8f5679d5f73425a
Reviewed-on: https://chromium-review.googlesource.com/1087587
Reviewed-by: Frank Liberato <[email protected]>
Reviewed-by: Emircan Uysaler <[email protected]>
Commit-Queue: CJ DiMeglio <[email protected]>
Cr-Commit-Position: refs/heads/master@{#582346}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f055d73..0d3bdea 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2874,6 +2874,10 @@
      flag_descriptions::kUseSurfaceLayerForVideoName,
      flag_descriptions::kUseSurfaceLayerForVideoDescription, kOsAll,
      FEATURE_VALUE_TYPE(media::kUseSurfaceLayerForVideo)},
+    {"enable-surfaces-for-videos-ms",
+     flag_descriptions::kUseSurfaceLayerForVideoMSName,
+     flag_descriptions::kUseSurfaceLayerForVideoMSDescription, kOsAll,
+     FEATURE_VALUE_TYPE(media::kUseSurfaceLayerForVideoMS)},
 #if defined(OS_CHROMEOS)
     {"quick-unlock-pin", flag_descriptions::kQuickUnlockPinName,
      flag_descriptions::kQuickUnlockPinDescription, kOsCrOS,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7202b08a9..5fb5141 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1159,6 +1159,11 @@
 const char kUseSurfaceLayerForVideoDescription[] =
     "Enable compositing onto a Surface instead of a VideoLayer "
     "for videos.";
+const char kUseSurfaceLayerForVideoMSName[] =
+    "Enable the use of SurfaceLayer objects for media stream videos.";
+const char kUseSurfaceLayerForVideoMSDescription[] =
+    "Enable compositing onto a Surface instead of a VideoLayer "
+    "for media stream videos.";
 
 const char kNewUsbBackendName[] = "Enable new USB backend";
 const char kNewUsbBackendDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 129eaa9..7984625b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -720,6 +720,9 @@
 extern const char kUseSurfaceLayerForVideoName[];
 extern const char kUseSurfaceLayerForVideoDescription[];
 
+extern const char kUseSurfaceLayerForVideoMSName[];
+extern const char kUseSurfaceLayerForVideoMSDescription[];
+
 extern const char kNewUsbBackendName[];
 extern const char kNewUsbBackendDescription[];
 
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index fe25c6b..a594229 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -153,6 +153,20 @@
          features::IsAshInBrowserProcess();
 }
 
+bool MediaFactory::VideoSurfaceLayerEnabledForMS() {
+  // LayoutTests do not support SurfaceLayer by default at the moment.
+  // See https://crbug.com/838128
+  content::RenderThreadImpl* render_thread =
+      content::RenderThreadImpl::current();
+  if (render_thread && render_thread->layout_test_mode() &&
+      !render_thread->LayoutTestModeUsesDisplayCompositorPixelDump()) {
+    return false;
+  }
+
+  return base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideoMS) &&
+         features::IsAshInBrowserProcess();
+}
+
 MediaFactory::MediaFactory(
     RenderFrameImpl* render_frame,
     media::RequestRoutingTokenCallback request_routing_token_cb)
@@ -214,7 +228,7 @@
       GetWebMediaStreamFromWebMediaPlayerSource(source);
   if (!web_stream.IsNull())
     return CreateWebMediaPlayerForMediaStream(client, sink_id, security_origin,
-                                              web_frame);
+                                              web_frame, layer_tree_view);
 
   // If |source| was not a MediaStream, it must be a URL.
   // TODO(guidou): Fix this when support for other srcObject types is added.
@@ -507,7 +521,8 @@
     blink::WebMediaPlayerClient* client,
     const blink::WebString& sink_id,
     const blink::WebSecurityOrigin& security_origin,
-    blink::WebLocalFrame* frame) {
+    blink::WebLocalFrame* frame,
+    blink::WebLayerTreeView* layer_tree_view) {
   RenderThreadImpl* const render_thread = RenderThreadImpl::current();
 
   scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner =
@@ -516,6 +531,7 @@
     compositor_task_runner =
         render_frame_->GetTaskRunner(blink::TaskType::kInternalMediaRealTime);
 
+  DCHECK(layer_tree_view);
   return new WebMediaPlayerMS(
       frame, client, GetWebMediaPlayerDelegate(),
       std::make_unique<RenderMediaLog>(
@@ -524,7 +540,9 @@
       CreateMediaStreamRendererFactory(), render_thread->GetIOTaskRunner(),
       compositor_task_runner, render_thread->GetMediaThreadTaskRunner(),
       render_thread->GetWorkerTaskRunner(), render_thread->GetGpuFactories(),
-      sink_id);
+      sink_id,
+      base::BindOnce(&blink::WebSurfaceLayerBridge::Create, layer_tree_view),
+      VideoSurfaceLayerEnabledForMS());
 }
 
 media::RendererWebMediaPlayerDelegate*
diff --git a/content/renderer/media/media_factory.h b/content/renderer/media/media_factory.h
index 7c4ea97..bbb8837e 100644
--- a/content/renderer/media/media_factory.h
+++ b/content/renderer/media/media_factory.h
@@ -74,6 +74,10 @@
   // Helper function returning whether VideoSurfaceLayer should be enabled.
   static bool VideoSurfaceLayerEnabled();
 
+  // Helper function returning whether VideoSurfaceLayer should be enabled for
+  // MediaStreams.
+  static bool VideoSurfaceLayerEnabledForMS();
+
   // Create a MediaFactory to assist the |render_frame| with media tasks.
   // |request_routing_token_cb| bound to |render_frame| IPC functions for
   // obtaining overlay tokens.
@@ -122,7 +126,8 @@
       blink::WebMediaPlayerClient* client,
       const blink::WebString& sink_id,
       const blink::WebSecurityOrigin& security_origin,
-      blink::WebLocalFrame* frame);
+      blink::WebLocalFrame* frame,
+      blink::WebLayerTreeView* layer_tree_view);
 
   // Returns the media delegate for WebMediaPlayer usage.  If
   // |media_player_delegate_| is NULL, one is created.
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc
index bf6ffa5..d071c391 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/public/platform/web_media_player_source.h"
 #include "third_party/blink/public/platform/web_rect.h"
 #include "third_party/blink/public/platform/web_size.h"
+#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 
 namespace {
@@ -262,7 +263,9 @@
     scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
     scoped_refptr<base::TaskRunner> worker_task_runner,
     media::GpuVideoAcceleratorFactories* gpu_factories,
-    const blink::WebString& sink_id)
+    const blink::WebString& sink_id,
+    CreateSurfaceLayerBridgeCB create_bridge_callback,
+    bool surface_layer_for_video_enabled)
     : frame_(frame),
       network_state_(WebMediaPlayer::kNetworkStateEmpty),
       ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
@@ -282,7 +285,9 @@
       initial_audio_output_device_id_(sink_id.Utf8()),
       volume_(1.0),
       volume_multiplier_(1.0),
-      should_play_upon_shown_(false) {
+      should_play_upon_shown_(false),
+      create_bridge_callback_(std::move(create_bridge_callback)),
+      surface_layer_for_video_enabled_(surface_layer_for_video_enabled) {
   DVLOG(1) << __func__;
   DCHECK(client);
   DCHECK(delegate_);
@@ -301,8 +306,10 @@
 
   // Destruct compositor resources in the proper order.
   get_client()->SetCcLayer(nullptr);
-  if (video_layer_)
+  if (video_layer_) {
+    DCHECK(!surface_layer_for_video_enabled_);
     video_layer_->StopUsingProvider();
+  }
 
   if (frame_deliverer_)
     io_task_runner_->DeleteSoon(FROM_HERE, frame_deliverer_.release());
@@ -418,6 +425,27 @@
   return blink::WebMediaPlayer::LoadTiming::kImmediate;
 }
 
+void WebMediaPlayerMS::OnWebLayerUpdated() {}
+
+void WebMediaPlayerMS::RegisterContentsLayer(cc::Layer* layer) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(bridge_);
+
+  bridge_->SetContentsOpaque(opaque_);
+  client_->SetCcLayer(layer);
+}
+
+void WebMediaPlayerMS::UnregisterContentsLayer(cc::Layer* layer) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // |client_| will unregister its cc::Layer if given a nullptr.
+  client_->SetCcLayer(nullptr);
+}
+
+void WebMediaPlayerMS::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
+  // TODO(apacible): Add implementation. See http://crbug/746182.
+  NOTIMPLEMENTED();
+}
+
 void WebMediaPlayerMS::TrackAdded(const blink::WebMediaStreamTrack& track) {
   Reload();
 }
@@ -1013,6 +1041,15 @@
                                             bool is_opaque) {
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (surface_layer_for_video_enabled_) {
+    DCHECK(!bridge_);
+
+    bridge_ = std::move(create_bridge_callback_)
+                  .Run(this, compositor_->GetUpdateSubmissionStateCallback());
+    bridge_->CreateSurfaceLayer();
+  }
+
   SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
   SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
 
@@ -1023,9 +1060,17 @@
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // Opacity can be changed during the session without resetting
-  // |video_layer_|.
-  video_layer_->SetContentsOpaque(is_opaque);
+  opaque_ = is_opaque;
+
+  if (!bridge_) {
+    // Opacity can be changed during the session without resetting
+    // |video_layer_|.
+    video_layer_->SetContentsOpaque(opaque_);
+  } else {
+    DCHECK(bridge_);
+
+    bridge_->SetContentsOpaque(opaque_);
+  }
 }
 
 void WebMediaPlayerMS::OnRotationChanged(media::VideoRotation video_rotation,
@@ -1033,16 +1078,22 @@
   DVLOG(1) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
   video_rotation_ = video_rotation;
+  opaque_ = is_opaque;
 
-  // Keep the old |video_layer_| alive until SetCcLayer() is called with a new
-  // pointer, as it may use the pointer from the last call.
-  auto new_video_layer =
-      cc::VideoLayer::Create(compositor_.get(), video_rotation);
-  new_video_layer->SetContentsOpaque(is_opaque);
+  if (!bridge_) {
+    // Keep the old |video_layer_| alive until SetCcLayer() is called with a new
+    // pointer, as it may use the pointer from the last call.
+    auto new_video_layer =
+        cc::VideoLayer::Create(compositor_.get(), video_rotation);
+    new_video_layer->SetContentsOpaque(is_opaque);
 
-  get_client()->SetCcLayer(new_video_layer.get());
+    get_client()->SetCcLayer(new_video_layer.get());
 
-  video_layer_ = std::move(new_video_layer);
+    video_layer_ = std::move(new_video_layer);
+  } else if (bridge_->GetCcLayer()) {
+    // TODO(lethalantidote): Handle rotation.
+    bridge_->SetContentsOpaque(opaque_);
+  }
 }
 
 void WebMediaPlayerMS::RepaintInternal() {
diff --git a/content/renderer/media/stream/webmediaplayer_ms.h b/content/renderer/media/stream/webmediaplayer_ms.h
index 8c0b492f..1857e62 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.h
+++ b/content/renderer/media/stream/webmediaplayer_ms.h
@@ -21,6 +21,7 @@
 #include "media/video/gpu_video_accelerator_factories.h"
 #include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/public/platform/web_media_stream.h"
+#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
 
 namespace blink {
 class WebLocalFrame;
@@ -44,6 +45,11 @@
 }
 
 namespace content {
+using CreateSurfaceLayerBridgeCB =
+    base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
+        blink::WebSurfaceLayerBridgeObserver*,
+        cc::UpdateSubmissionStateCB)>;
+
 class MediaStreamAudioRenderer;
 class MediaStreamRendererFactory;
 class MediaStreamVideoRenderer;
@@ -66,6 +72,7 @@
     : public blink::WebMediaStreamObserver,
       public blink::WebMediaPlayer,
       public media::WebMediaPlayerDelegate::Observer,
+      public blink::WebSurfaceLayerBridgeObserver,
       public base::SupportsWeakPtr<WebMediaPlayerMS> {
  public:
   // Construct a WebMediaPlayerMS with reference to the client, and
@@ -82,7 +89,9 @@
       scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
       scoped_refptr<base::TaskRunner> worker_task_runner,
       media::GpuVideoAcceleratorFactories* gpu_factories,
-      const blink::WebString& sink_id);
+      const blink::WebString& sink_id,
+      CreateSurfaceLayerBridgeCB create_bridge_callback,
+      bool surface_layer_for_video_enabled_);
 
   ~WebMediaPlayerMS() override;
 
@@ -91,6 +100,12 @@
       const blink::WebMediaPlayerSource& source,
       CORSMode cors_mode) override;
 
+  // WebSurfaceLayerBridgeObserver implementation.
+  void OnWebLayerUpdated() override;
+  void RegisterContentsLayer(cc::Layer* layer) override;
+  void UnregisterContentsLayer(cc::Layer* layer) override;
+  void OnSurfaceIdUpdated(viz::SurfaceId surface_id) override;
+
   // Playback controls.
   void Play() override;
   void Pause() override;
@@ -306,6 +321,18 @@
   blink::WebString current_video_track_id_;
   blink::WebString current_audio_track_id_;
 
+  CreateSurfaceLayerBridgeCB create_bridge_callback_;
+
+  // Whether the use of a surface layer instead of a video layer is enabled.
+  bool surface_layer_for_video_enabled_ = false;
+
+  // Owns the weblayer and obtains/maintains SurfaceIds for
+  // kUseSurfaceLayerForVideo feature.
+  std::unique_ptr<blink::WebSurfaceLayerBridge> bridge_;
+
+  // Whether the video is known to be opaque or not.
+  bool opaque_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerMS);
 };
 
diff --git a/content/renderer/media/stream/webmediaplayer_ms_compositor.h b/content/renderer/media/stream/webmediaplayer_ms_compositor.h
index 002b4c4..921b0bb 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_compositor.h
+++ b/content/renderer/media/stream/webmediaplayer_ms_compositor.h
@@ -16,6 +16,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "cc/layers/surface_layer.h"
 #include "cc/layers/video_frame_provider.h"
 #include "content/common/content_export.h"
 #include "media/base/media_log.h"
@@ -62,6 +63,11 @@
       const blink::WebMediaStream& web_stream,
       const base::WeakPtr<WebMediaPlayerMS>& player);
 
+  // Can be called from any thread.
+  cc::UpdateSubmissionStateCB GetUpdateSubmissionStateCallback() {
+    return update_submission_state_callback_;
+  }
+
   void EnqueueFrame(scoped_refptr<media::VideoFrame> frame);
 
   // Statistical data
@@ -182,6 +188,8 @@
 
   std::map<base::TimeDelta, base::TimeTicks> timestamps_to_clock_times_;
 
+  cc::UpdateSubmissionStateCB update_submission_state_callback_;
+
   // |current_frame_lock_| protects |current_frame_|, |rendering_frame_buffer_|,
   // |dropped_frame_count_|, and |render_started_|.
   base::Lock current_frame_lock_;
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
index 8f01703e..89994de8 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -26,6 +26,9 @@
 #include "third_party/blink/public/platform/web_media_player_client.h"
 #include "third_party/blink/public/platform/web_media_player_source.h"
 
+using ::testing::Return;
+using ::testing::StrictMock;
+
 namespace content {
 
 enum class FrameType {
@@ -35,6 +38,16 @@
   MIN_TYPE = TEST_BRAKE
 };
 
+class MockSurfaceLayerBridge : public blink::WebSurfaceLayerBridge {
+ public:
+  MOCK_CONST_METHOD0(GetCcLayer, cc::Layer*());
+  MOCK_CONST_METHOD0(GetFrameSinkId, const viz::FrameSinkId&());
+  MOCK_CONST_METHOD0(GetSurfaceId, const viz::SurfaceId&());
+  MOCK_METHOD1(SetContentsOpaque, void(bool));
+  MOCK_METHOD0(CreateSurfaceLayer, void());
+  MOCK_METHOD0(ClearSurfaceId, void());
+};
+
 using TestFrame = std::pair<FrameType, scoped_refptr<media::VideoFrame>>;
 
 static const int kOddSizeOffset = 3;
@@ -493,26 +506,20 @@
       : render_factory_(new MockRenderFactory(message_loop_.task_runner(),
                                               &message_loop_controller_)),
         gpu_factories_(new media::MockGpuVideoAcceleratorFactories(nullptr)),
-        player_(new WebMediaPlayerMS(
-            nullptr,
-            this,
-            &delegate_,
-            std::make_unique<media::MediaLog>(),
-            std::unique_ptr<MediaStreamRendererFactory>(render_factory_),
-            message_loop_.task_runner(),
-            message_loop_.task_runner(),
-            message_loop_.task_runner(),
-            message_loop_.task_runner(),
-            gpu_factories_.get(),
-            blink::WebString())),
+        surface_layer_bridge_(
+            std::make_unique<StrictMock<MockSurfaceLayerBridge>>()),
         layer_set_(false),
         rendering_(false),
-        background_rendering_(false) {}
+        background_rendering_(false) {
+    surface_layer_bridge_ptr_ = surface_layer_bridge_.get();
+  }
   ~WebMediaPlayerMSTest() override {
     player_.reset();
     base::RunLoop().RunUntilIdle();
   }
 
+  void InitializeWebMediaPlayerMS(bool enable_surface_layer_for_video);
+
   MockMediaStreamVideoRenderer* LoadAndGetFrameProvider(bool algorithm_enabled);
 
   // Implementation of WebMediaPlayerClient
@@ -608,6 +615,12 @@
   MOCK_METHOD1(CheckSizeChanged, void(gfx::Size));
   MOCK_CONST_METHOD0(CouldPlayIfEnoughData, bool());
 
+  std::unique_ptr<blink::WebSurfaceLayerBridge> CreateMockSurfaceLayerBridge(
+      blink::WebSurfaceLayerBridgeObserver*,
+      cc::UpdateSubmissionStateCB) {
+    return std::move(surface_layer_bridge_);
+  }
+
   base::MessageLoop message_loop_;
   MockRenderFactory* render_factory_;
   std::unique_ptr<media::MockGpuVideoAcceleratorFactories> gpu_factories_;
@@ -618,6 +631,8 @@
   cc::Layer* layer_;
   bool is_audio_element_ = false;
   std::vector<base::OnceClosure> frame_ready_cbs_;
+  std::unique_ptr<StrictMock<MockSurfaceLayerBridge>> surface_layer_bridge_;
+  StrictMock<MockSurfaceLayerBridge>* surface_layer_bridge_ptr_ = nullptr;
 
  private:
   // Main function trying to ask WebMediaPlayerMS to submit a frame for
@@ -629,6 +644,19 @@
   bool background_rendering_;
 };
 
+void WebMediaPlayerMSTest::InitializeWebMediaPlayerMS(
+    bool enable_surface_layer_for_video) {
+  player_ = std::make_unique<WebMediaPlayerMS>(
+      nullptr, this, &delegate_, std::make_unique<media::MediaLog>(),
+      std::unique_ptr<MediaStreamRendererFactory>(render_factory_),
+      message_loop_.task_runner(), message_loop_.task_runner(),
+      message_loop_.task_runner(), message_loop_.task_runner(),
+      gpu_factories_.get(), blink::WebString(),
+      base::BindRepeating(&WebMediaPlayerMSTest::CreateMockSurfaceLayerBridge,
+                          base::Unretained(this)),
+      enable_surface_layer_for_video);
+}
+
 MockMediaStreamVideoRenderer* WebMediaPlayerMSTest::LoadAndGetFrameProvider(
     bool algorithm_enabled) {
   EXPECT_FALSE(!!render_factory_->provider()) << "There should not be a "
@@ -742,6 +770,7 @@
 }
 
 TEST_F(WebMediaPlayerMSTest, NoDataDuringLoadForVideo) {
+  InitializeWebMediaPlayerMS(false);
   EXPECT_CALL(*this, DoReadyStateChanged(
                          blink::WebMediaPlayer::kReadyStateHaveMetadata))
       .Times(0);
@@ -759,6 +788,7 @@
 }
 
 TEST_F(WebMediaPlayerMSTest, NoWaitForFrameForAudio) {
+  InitializeWebMediaPlayerMS(false);
   is_audio_element_ = true;
   scoped_refptr<MediaStreamAudioRenderer> audio_renderer(
       new MockMediaStreamAudioRenderer());
@@ -785,6 +815,7 @@
 }
 
 TEST_F(WebMediaPlayerMSTest, NoWaitForFrameForAudioOnly) {
+  InitializeWebMediaPlayerMS(false);
   render_factory_->set_support_video_renderer(false);
   scoped_refptr<MediaStreamAudioRenderer> audio_renderer(
       new MockMediaStreamAudioRenderer());
@@ -802,6 +833,8 @@
   // and verifies that they are produced by WebMediaPlayerMS in appropriate
   // order.
 
+  InitializeWebMediaPlayerMS(false);
+
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
 
   int tokens[] = {0,   33,  66,  100, 133, 166, 200, 233, 266, 300,
@@ -832,6 +865,8 @@
   // This tests sends a broken frame to WebMediaPlayerMS, and verifies
   // OnSourceError function works as expected.
 
+  InitializeWebMediaPlayerMS(false);
+
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(false);
 
   const int kBrokenFrame = static_cast<int>(FrameType::BROKEN_FRAME);
@@ -859,6 +894,7 @@
 }
 
 TEST_P(WebMediaPlayerMSTest, PlayThenPause) {
+  InitializeWebMediaPlayerMS(false);
   const bool opaque_frame = testing::get<0>(GetParam());
   const bool odd_size_frame = testing::get<1>(GetParam());
   // In the middle of this test, WebMediaPlayerMS::pause will be called, and we
@@ -900,6 +936,7 @@
 }
 
 TEST_P(WebMediaPlayerMSTest, PlayThenPauseThenPlay) {
+  InitializeWebMediaPlayerMS(false);
   const bool opaque_frame = testing::get<0>(GetParam());
   const bool odd_size_frame = testing::get<1>(GetParam());
   // Similary to PlayAndPause test above, this one focuses on testing that
@@ -959,6 +996,7 @@
 // During this test, we check that when we send rotated video frames, it applies
 // to player's natural size.
 TEST_F(WebMediaPlayerMSTest, RotationChange) {
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
 
   const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE);
@@ -999,6 +1037,7 @@
 // During this test, we check that web layer changes opacity according to the
 // given frames.
 TEST_F(WebMediaPlayerMSTest, OpacityChange) {
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
 
   // Push one opaque frame.
@@ -1043,6 +1082,7 @@
   // WebMediaPlayerMS without an explicit notification. We should expect that
   // WebMediaPlayerMS can digest old frames, rather than piling frames up and
   // explode.
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
 
   const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE);
@@ -1091,6 +1131,7 @@
   // During this test, the frame size of the input changes.
   // We need to make sure, when sizeChanged() gets called, new size should be
   // returned by GetCurrentSize().
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
 
   int tokens[] = {0,   33,  66,  100, 133, 166, 200, 233, 266, 300,
@@ -1119,6 +1160,7 @@
 // Tests that GpuMemoryBufferVideoFramePool is called in the expected sequence.
 // TODO(https://crbug.com/831327): Flaky under load / CPU scheduling delays.
 TEST_F(WebMediaPlayerMSTest, DISABLED_CreateHardwareFrames) {
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
   SetGpuMemoryBufferVideoForTesting();
 
@@ -1156,6 +1198,7 @@
 // TODO(https://crbug.com/831327): Flaky under load / CPU scheduling delays.
 TEST_F(WebMediaPlayerMSTest,
        DISABLED_StopsCreatingHardwareFramesWhenHiddenOrClosed) {
+  InitializeWebMediaPlayerMS(false);
   MockMediaStreamVideoRenderer* provider = LoadAndGetFrameProvider(true);
   SetGpuMemoryBufferVideoForTesting();
 
@@ -1213,6 +1256,7 @@
 
 #if defined(OS_ANDROID)
 TEST_F(WebMediaPlayerMSTest, HiddenPlayerTests) {
+  InitializeWebMediaPlayerMS(false);
   LoadAndGetFrameProvider(true);
 
   // Hidden status should not affect playback.
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 7361893..4610d85 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -325,6 +325,10 @@
 const base::Feature kUseSurfaceLayerForVideo{"UseSurfaceLayerForVideo",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Use SurfaceLayer instead of VideoLayer for MediaStream.
+const base::Feature kUseSurfaceLayerForVideoMS{
+    "UseSurfaceLayerForVideoMS", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable VA-API hardware encode acceleration for VP8.
 const base::Feature kVaapiVP8Encoder{"VaapiVP8Encoder",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 967fd507..6be16b7 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -138,6 +138,7 @@
 MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
 MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo;
+MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideoMS;
 MEDIA_EXPORT extern const base::Feature kUseModernMediaControls;
 
 #if defined(OS_ANDROID)
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 12694a6..330194f 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -879,10 +879,7 @@
   // Whether the use of a surface layer instead of a video layer is enabled.
   bool surface_layer_for_video_enabled_ = false;
 
-  base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
-      blink::WebSurfaceLayerBridgeObserver*,
-      cc::UpdateSubmissionStateCB)>
-      create_bridge_callback_;
+  CreateSurfaceLayerBridgeCB create_bridge_callback_;
 
   base::CancelableOnceCallback<void(base::TimeTicks)> frame_time_report_cb_;
 
diff --git a/media/blink/webmediaplayer_params.cc b/media/blink/webmediaplayer_params.cc
index 0436885..42317de1 100644
--- a/media/blink/webmediaplayer_params.cc
+++ b/media/blink/webmediaplayer_params.cc
@@ -28,9 +28,7 @@
     bool enable_instant_source_buffer_gc,
     bool embedded_media_experience_enabled,
     mojom::MediaMetricsProviderPtr metrics_provider,
-    base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
-        blink::WebSurfaceLayerBridgeObserver*,
-        cc::UpdateSubmissionStateCB)> create_bridge_callback,
+    CreateSurfaceLayerBridgeCB create_bridge_callback,
     scoped_refptr<viz::ContextProvider> context_provider,
     bool use_surface_layer_for_video)
     : defer_load_cb_(defer_load_cb),
diff --git a/media/blink/webmediaplayer_params.h b/media/blink/webmediaplayer_params.h
index 0793f19..21b132e 100644
--- a/media/blink/webmediaplayer_params.h
+++ b/media/blink/webmediaplayer_params.h
@@ -37,6 +37,11 @@
 
 namespace media {
 
+using CreateSurfaceLayerBridgeCB =
+    base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
+        blink::WebSurfaceLayerBridgeObserver*,
+        cc::UpdateSubmissionStateCB)>;
+
 class SwitchableAudioRendererSink;
 
 // Holds parameters for constructing WebMediaPlayerImpl without having
@@ -81,9 +86,7 @@
       bool enable_instant_source_buffer_gc,
       bool embedded_media_experience_enabled,
       mojom::MediaMetricsProviderPtr metrics_provider,
-      base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
-          blink::WebSurfaceLayerBridgeObserver*,
-          cc::UpdateSubmissionStateCB)> bridge_callback,
+      CreateSurfaceLayerBridgeCB bridge_callback,
       scoped_refptr<viz::ContextProvider> context_provider,
       bool use_surface_layer_for_video);
 
@@ -153,10 +156,7 @@
     return request_routing_token_cb_;
   }
 
-  base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
-      blink::WebSurfaceLayerBridgeObserver*,
-      cc::UpdateSubmissionStateCB)>
-  create_bridge_callback() {
+  CreateSurfaceLayerBridgeCB create_bridge_callback() {
     return std::move(create_bridge_callback_);
   }
 
@@ -187,10 +187,7 @@
   bool enable_instant_source_buffer_gc_;
   const bool embedded_media_experience_enabled_;
   mojom::MediaMetricsProviderPtr metrics_provider_;
-  base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>(
-      blink::WebSurfaceLayerBridgeObserver*,
-      cc::UpdateSubmissionStateCB)>
-      create_bridge_callback_;
+  CreateSurfaceLayerBridgeCB create_bridge_callback_;
   scoped_refptr<viz::ContextProvider> context_provider_;
   bool use_surface_layer_for_video_;
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2ae0bac..3c50b505 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -29505,6 +29505,7 @@
   <int value="1689183477" label="enable-merge-key-char-events"/>
   <int value="1690837904" label="save-previous-document-resources"/>
   <int value="1691568199" label="AndroidSpellCheckerNonLowEnd:disabled"/>
+  <int value="1694562245" label="UseSurfaceLayerForVideoMS:disabled"/>
   <int value="1694766748"
       label="AutofillRestrictUnownedFieldsToFormlessCheckout:enabled"/>
   <int value="1694798717" label="NewNetErrorPageUI:enabled"/>
@@ -29591,6 +29592,7 @@
   <int value="1862207743" label="enable-android-spellchecker"/>
   <int value="1863622457" label="WebAuthentication:enabled"/>
   <int value="1865068568" label="disable-audio-support-for-desktop-share"/>
+  <int value="1865702649" label="UseSurfaceLayerForVideoMS:enabled"/>
   <int value="1865799183" label="javascript-harmony"/>
   <int value="1865963858" label="tls13-variant"/>
   <int value="1866079109" label="team-drives"/>