Merge "Cherry-pick: [Android WebView] Fix crash in M38 WebView." into m38
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
index e624e9b..f5cc135 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
 
+#include "base/observer_list.h"
 #include "content/browser/android/in_process/synchronous_compositor_output_surface.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/renderer/gpu/frame_swap_message_queue.h"
@@ -104,7 +105,9 @@
           context.Pass(), attributes));
 }
 
-class VideoContextProvider
+}  // namespace
+
+class SynchronousCompositorFactoryImpl::VideoContextProvider
     : public StreamTextureFactorySynchronousImpl::ContextProvider {
  public:
   VideoContextProvider(
@@ -126,18 +129,32 @@
     return context_provider_->ContextGL();
   }
 
+  virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE {
+    observer_list_.AddObserver(obs);
+  }
+
+  virtual void RemoveObserver(
+      StreamTextureFactoryContextObserver* obs) OVERRIDE {
+    observer_list_.RemoveObserver(obs);
+  }
+
+  void RestoreContext() {
+    FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
+                      observer_list_,
+                      ResetStreamTextureProxy());
+  }
+
  private:
   friend class base::RefCountedThreadSafe<VideoContextProvider>;
   virtual ~VideoContextProvider() {}
 
   scoped_refptr<cc::ContextProvider> context_provider_;
   gpu::GLInProcessContext* gl_in_process_context_;
+  ObserverList<StreamTextureFactoryContextObserver> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
 };
 
-}  // namespace
-
 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
 
 SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
@@ -226,6 +243,13 @@
 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() {
   base::AutoLock lock(num_hardware_compositor_lock_);
   num_hardware_compositors_++;
+  if (num_hardware_compositors_ == 1 && main_thread_proxy_) {
+    main_thread_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &SynchronousCompositorFactoryImpl::RestoreContextOnMainThread,
+            base::Unretained(this)));
+  }
 }
 
 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
@@ -234,6 +258,11 @@
   num_hardware_compositors_--;
 }
 
+void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
+  if (CanCreateMainThreadContext() && video_context_provider_ )
+    video_context_provider_->RestoreContext();
+}
+
 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
   base::AutoLock lock(num_hardware_compositor_lock_);
   return num_hardware_compositors_ > 0;
@@ -241,6 +270,11 @@
 
 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
+  {
+    base::AutoLock lock(num_hardware_compositor_lock_);
+    main_thread_proxy_ = base::MessageLoopProxy::current();
+  }
+
   // Always fail creation even if |video_context_provider_| is not NULL.
   // This is to avoid synchronous calls that may deadlock. Setting
   // |video_context_provider_| to null is also not safe since it makes
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.h b/content/browser/android/in_process/synchronous_compositor_factory_impl.h
index 0c3cb7c..0b8ae55 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.h
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.h
@@ -66,13 +66,15 @@
   bool CanCreateMainThreadContext();
   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
       TryCreateStreamTextureFactory();
+  void RestoreContextOnMainThread();
 
   SynchronousInputEventFilter synchronous_input_event_filter_;
 
   scoped_refptr<gpu::InProcessCommandBuffer::Service> service_;
   scoped_ptr<gpu::GLInProcessContext> share_context_;
-  scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
-      video_context_provider_;
+
+  class VideoContextProvider;
+  scoped_refptr<VideoContextProvider> video_context_provider_;
 
   bool record_full_layer_;
 
@@ -80,6 +82,7 @@
   // read on renderer main thread.
   base::Lock num_hardware_compositor_lock_;
   unsigned int num_hardware_compositors_;
+  scoped_refptr<base::MessageLoopProxy> main_thread_proxy_;
 };
 
 }  // namespace content
diff --git a/content/renderer/media/android/stream_texture_factory.h b/content/renderer/media/android/stream_texture_factory.h
index 70d31e9..8d04800 100644
--- a/content/renderer/media/android/stream_texture_factory.h
+++ b/content/renderer/media/android/stream_texture_factory.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "cc/layers/video_frame_provider.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ui/gfx/size.h"
@@ -25,13 +26,12 @@
  public:
   virtual ~StreamTextureProxy() {}
 
-  // Initialize and bind to the current thread, which becomes the thread that
-  // a connected client will receive callbacks on.
-  virtual void BindToCurrentThread(int32 stream_id) = 0;
-
-  // Setting the target for callback when a frame is available. This function
-  // could be called on both the main thread and the compositor thread.
-  virtual void SetClient(cc::VideoFrameProvider::Client* client) = 0;
+  // Initialize and bind to the loop, which becomes the thread that
+  // a connected client will receive callbacks on. This can be called
+  // on any thread, but must be called with the same loop every time.
+  virtual void BindToLoop(int32 stream_id,
+                          cc::VideoFrameProvider::Client* client,
+                          scoped_refptr<base::MessageLoopProxy> loop) = 0;
 
   // Causes this instance to be deleted on the thread it is bound to.
   virtual void Release() = 0;
@@ -44,6 +44,12 @@
 typedef scoped_ptr<StreamTextureProxy, StreamTextureProxy::Deleter>
     ScopedStreamTextureProxy;
 
+class StreamTextureFactoryContextObserver {
+ public:
+  virtual ~StreamTextureFactoryContextObserver() {}
+  virtual void ResetStreamTextureProxy() = 0;
+};
+
 // Factory class for managing stream textures.
 class StreamTextureFactory : public base::RefCounted<StreamTextureFactory> {
  public:
@@ -69,6 +75,9 @@
 
   virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
 
+  virtual void AddObserver(StreamTextureFactoryContextObserver* obs) = 0;
+  virtual void RemoveObserver(StreamTextureFactoryContextObserver* obs) = 0;
+
  protected:
   friend class base::RefCounted<StreamTextureFactory>;
   virtual ~StreamTextureFactory() {}
diff --git a/content/renderer/media/android/stream_texture_factory_impl.cc b/content/renderer/media/android/stream_texture_factory_impl.cc
index da9a70f..a8b9a32 100644
--- a/content/renderer/media/android/stream_texture_factory_impl.cc
+++ b/content/renderer/media/android/stream_texture_factory_impl.cc
@@ -22,8 +22,9 @@
   virtual ~StreamTextureProxyImpl();
 
   // StreamTextureProxy implementation:
-  virtual void BindToCurrentThread(int32 stream_id) OVERRIDE;
-  virtual void SetClient(cc::VideoFrameProvider::Client* client) OVERRIDE;
+  virtual void BindToLoop(int32 stream_id,
+                          cc::VideoFrameProvider::Client* client,
+                          scoped_refptr<base::MessageLoopProxy> loop) OVERRIDE;
   virtual void Release() OVERRIDE;
 
   // StreamTextureHost::Listener implementation:
@@ -31,11 +32,13 @@
   virtual void OnMatrixChanged(const float matrix[16]) OVERRIDE;
 
  private:
-  scoped_ptr<StreamTextureHost> host_;
-  scoped_refptr<base::MessageLoopProxy> loop_;
+  void BindOnThread(int32 stream_id);
 
-  base::Lock client_lock_;
+  const scoped_ptr<StreamTextureHost> host_;
+
+  base::Lock lock_;
   cc::VideoFrameProvider::Client* client_;
+  scoped_refptr<base::MessageLoopProxy> loop_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl);
 };
@@ -46,31 +49,55 @@
 StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
 
 void StreamTextureProxyImpl::Release() {
-  SetClient(NULL);
-  if (loop_.get() && loop_.get() != base::MessageLoopProxy::current())
-    loop_->DeleteSoon(FROM_HERE, this);
-  else
+  {
+    base::AutoLock lock(lock_);
+    client_ = NULL;
+  }
+  // Assumes this is the last reference to this object. So no need to acquire
+  // lock.
+  if (!loop_.get() || loop_->BelongsToCurrentThread() ||
+      !loop_->DeleteSoon(FROM_HERE, this)) {
     delete this;
+  }
 }
 
-void StreamTextureProxyImpl::SetClient(cc::VideoFrameProvider::Client* client) {
-  base::AutoLock lock(client_lock_);
-  client_ = client;
+void StreamTextureProxyImpl::BindToLoop(
+    int32 stream_id,
+    cc::VideoFrameProvider::Client* client,
+    scoped_refptr<base::MessageLoopProxy> loop) {
+  DCHECK(loop);
+
+  {
+    base::AutoLock lock(lock_);
+    DCHECK(!loop_ || (loop == loop_));
+    loop_ = loop;
+    client_ = client;
+  }
+
+  if (loop->BelongsToCurrentThread()) {
+    BindOnThread(stream_id);
+    return;
+  }
+  // Unretained is safe here only because the object is deleted on |loop_|
+  // thread.
+  loop->PostTask(FROM_HERE,
+                 base::Bind(&StreamTextureProxyImpl::BindOnThread,
+                            base::Unretained(this),
+                            stream_id));
 }
 
-void StreamTextureProxyImpl::BindToCurrentThread(int stream_id) {
-  loop_ = base::MessageLoopProxy::current();
+void StreamTextureProxyImpl::BindOnThread(int32 stream_id) {
   host_->BindToCurrentThread(stream_id, this);
 }
 
 void StreamTextureProxyImpl::OnFrameAvailable() {
-  base::AutoLock lock(client_lock_);
+  base::AutoLock lock(lock_);
   if (client_)
     client_->DidReceiveFrame();
 }
 
 void StreamTextureProxyImpl::OnMatrixChanged(const float matrix[16]) {
-  base::AutoLock lock(client_lock_);
+  base::AutoLock lock(lock_);
   if (client_)
     client_->DidUpdateMatrix(matrix);
 }
@@ -134,4 +161,12 @@
   return context_provider_->ContextGL();
 }
 
+void StreamTextureFactoryImpl::AddObserver(
+    StreamTextureFactoryContextObserver* obs) {
+}
+
+void StreamTextureFactoryImpl::RemoveObserver(
+    StreamTextureFactoryContextObserver* obs) {
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/stream_texture_factory_impl.h b/content/renderer/media/android/stream_texture_factory_impl.h
index 7721c48..62586b0 100644
--- a/content/renderer/media/android/stream_texture_factory_impl.h
+++ b/content/renderer/media/android/stream_texture_factory_impl.h
@@ -37,6 +37,9 @@
   virtual void SetStreamTextureSize(int32 texture_id,
                                     const gfx::Size& size) OVERRIDE;
   virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE;
+  virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE;
+  virtual void RemoveObserver(
+      StreamTextureFactoryContextObserver* obs) OVERRIDE;
 
  private:
   friend class base::RefCounted<StreamTextureFactoryImpl>;
diff --git a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
index 20c8ee7..1057213 100644
--- a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
+++ b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
@@ -34,22 +34,24 @@
   virtual ~StreamTextureProxyImpl();
 
   // StreamTextureProxy implementation:
-  virtual void BindToCurrentThread(int32 stream_id) OVERRIDE;
-  virtual void SetClient(cc::VideoFrameProvider::Client* client) OVERRIDE;
+  virtual void BindToLoop(int32 stream_id,
+                          cc::VideoFrameProvider::Client* client,
+                          scoped_refptr<base::MessageLoopProxy> loop) OVERRIDE;
   virtual void Release() OVERRIDE;
 
  private:
+  void BindOnThread(int32 stream_id);
   void OnFrameAvailable();
 
-  scoped_refptr<base::MessageLoopProxy> loop_;
-  base::Lock client_lock_;
+  base::Lock lock_;
   cc::VideoFrameProvider::Client* client_;
-  base::Closure callback_;
+  scoped_refptr<base::MessageLoopProxy> loop_;
 
+  // Accessed on the |loop_| thread only.
+  base::Closure callback_;
   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
       context_provider_;
   scoped_refptr<gfx::SurfaceTexture> surface_texture_;
-
   float current_matrix_[16];
   bool has_updated_;
 
@@ -58,27 +60,51 @@
 
 StreamTextureProxyImpl::StreamTextureProxyImpl(
     StreamTextureFactorySynchronousImpl::ContextProvider* provider)
-    : context_provider_(provider), has_updated_(false) {
+    : client_(NULL), context_provider_(provider), has_updated_(false) {
   std::fill(current_matrix_, current_matrix_ + 16, 0);
 }
 
 StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
 
 void StreamTextureProxyImpl::Release() {
-  SetClient(NULL);
-  if (loop_.get() && !loop_->BelongsToCurrentThread())
-    loop_->DeleteSoon(FROM_HERE, this);
-  else
+  {
+    base::AutoLock lock(lock_);
+    client_ = NULL;
+  }
+  // Assumes this is the last reference to this object. So no need to acquire
+  // lock.
+  if (!loop_.get() || loop_->BelongsToCurrentThread() ||
+      !loop_->DeleteSoon(FROM_HERE, this)) {
     delete this;
+  }
 }
 
-void StreamTextureProxyImpl::SetClient(cc::VideoFrameProvider::Client* client) {
-  base::AutoLock lock(client_lock_);
-  client_ = client;
+void StreamTextureProxyImpl::BindToLoop(
+    int32 stream_id,
+    cc::VideoFrameProvider::Client* client,
+    scoped_refptr<base::MessageLoopProxy> loop) {
+  DCHECK(loop);
+
+  {
+    base::AutoLock lock(lock_);
+    DCHECK(!loop_ || (loop == loop_));
+    loop_ = loop;
+    client_ = client;
+  }
+
+  if (loop->BelongsToCurrentThread()) {
+    BindOnThread(stream_id);
+    return;
+  }
+  // Unretained is safe here only because the object is deleted on |loop_|
+  // thread.
+  loop->PostTask(FROM_HERE,
+                 base::Bind(&StreamTextureProxyImpl::BindOnThread,
+                            base::Unretained(this),
+                            stream_id));
 }
 
-void StreamTextureProxyImpl::BindToCurrentThread(int stream_id) {
-  loop_ = base::MessageLoopProxy::current();
+void StreamTextureProxyImpl::BindOnThread(int32 stream_id) {
   surface_texture_ = context_provider_->GetSurfaceTexture(stream_id);
   if (!surface_texture_) {
     LOG(ERROR) << "Failed to get SurfaceTexture for stream.";
@@ -101,7 +127,7 @@
     if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) {
       memcpy(current_matrix_, matrix, sizeof(matrix));
 
-      base::AutoLock lock(client_lock_);
+      base::AutoLock lock(lock_);
       if (client_)
         client_->DidUpdateMatrix(current_matrix_);
     }
@@ -110,7 +136,7 @@
   // updateTexImage since after we received the first frame.
   has_updated_ = true;
 
-  base::AutoLock lock(client_lock_);
+  base::AutoLock lock(lock_);
   if (client_)
     client_->DidReceiveFrame();
 }
@@ -130,7 +156,8 @@
     int frame_id)
     : create_context_provider_callback_(try_create_callback),
       context_provider_(create_context_provider_callback_.Run()),
-      frame_id_(frame_id) {}
+      frame_id_(frame_id),
+      observer_(NULL) {}
 
 StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {}
 
@@ -140,6 +167,9 @@
 
   if (!context_provider_)
     return NULL;
+
+  if (observer_)
+    context_provider_->AddObserver(observer_);
   return new StreamTextureProxyImpl(context_provider_);
 }
 
@@ -182,4 +212,20 @@
   return context_provider_->ContextGL();
 }
 
+void StreamTextureFactorySynchronousImpl::AddObserver(
+    StreamTextureFactoryContextObserver* obs) {
+  DCHECK(!observer_);
+  observer_ = obs;
+  if (context_provider_)
+    context_provider_->AddObserver(obs);
+}
+
+void StreamTextureFactorySynchronousImpl::RemoveObserver(
+    StreamTextureFactoryContextObserver* obs) {
+  DCHECK_EQ(observer_, obs);
+  observer_ = NULL;
+  if (context_provider_)
+    context_provider_->RemoveObserver(obs);
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/stream_texture_factory_synchronous_impl.h b/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
index 3466c56..460fce7 100644
--- a/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
+++ b/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
 #include "content/renderer/media/android/stream_texture_factory.h"
 
 namespace gfx {
@@ -31,6 +32,9 @@
 
     virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
 
+    virtual void AddObserver(StreamTextureFactoryContextObserver* obs) = 0;
+    virtual void RemoveObserver(StreamTextureFactoryContextObserver* obs) = 0;
+
    protected:
     friend class base::RefCountedThreadSafe<ContextProvider>;
     virtual ~ContextProvider() {}
@@ -51,6 +55,9 @@
   virtual void SetStreamTextureSize(int32 stream_id,
                                     const gfx::Size& size) OVERRIDE;
   virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE;
+  virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE;
+  virtual void RemoveObserver(
+      StreamTextureFactoryContextObserver* obs) OVERRIDE;
 
  private:
   friend class base::RefCounted<StreamTextureFactorySynchronousImpl>;
@@ -62,6 +69,7 @@
   CreateContextProviderCallback create_context_provider_callback_;
   scoped_refptr<ContextProvider> context_provider_;
   int frame_id_;
+  StreamTextureFactoryContextObserver* observer_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureFactorySynchronousImpl);
 };
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 068fc06..e4ce0c2 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -134,8 +134,9 @@
       stream_id_(0),
       is_playing_(false),
       needs_establish_peer_(true),
-      stream_texture_proxy_initialized_(false),
       has_size_info_(false),
+      compositor_loop_(
+          RenderThreadImpl::current()->compositor_message_loop_proxy()),
       stream_texture_factory_(factory),
       needs_external_surface_(false),
       video_frame_provider_client_(NULL),
@@ -151,6 +152,7 @@
   DCHECK(cdm_manager_);
 
   DCHECK(main_thread_checker_.CalledOnValidThread());
+  stream_texture_factory_->AddObserver(this);
 
   player_id_ = player_manager_->RegisterMediaPlayer(this);
 
@@ -192,6 +194,8 @@
 
   if (player_type_ == MEDIA_PLAYER_TYPE_MEDIA_SOURCE && delegate_)
     delegate_->PlayerGone(this);
+
+  stream_texture_factory_->RemoveObserver(this);
 }
 
 void WebMediaPlayerAndroid::load(LoadType load_type,
@@ -1163,22 +1167,15 @@
     cc::VideoFrameProvider::Client* client) {
   // This is called from both the main renderer thread and the compositor
   // thread (when the main thread is blocked).
-  if (video_frame_provider_client_)
+
+  // Set the callback target when a frame is produced. Need to do this before
+  // StopUsingProvider to ensure we really stop using the client.
+  if (stream_texture_proxy_)
+    stream_texture_proxy_->BindToLoop(stream_id_, client, compositor_loop_);
+
+  if (video_frame_provider_client_ && video_frame_provider_client_ != client)
     video_frame_provider_client_->StopUsingProvider();
   video_frame_provider_client_ = client;
-
-  // Set the callback target when a frame is produced.
-  if (stream_texture_proxy_) {
-    stream_texture_proxy_->SetClient(client);
-    // If client exists, the compositor thread calls it. At that time,
-    // stream_id_, needs_external_surface_, is_remote_ can be accessed because
-    // the main thread is blocked.
-    if (client && !stream_texture_proxy_initialized_ && stream_id_ &&
-        !needs_external_surface_ && !is_remote_) {
-      stream_texture_proxy_->BindToCurrentThread(stream_id_);
-      stream_texture_proxy_initialized_ = true;
-    }
-  }
 }
 
 void WebMediaPlayerAndroid::SetCurrentFrameInternal(
@@ -1202,6 +1199,26 @@
     const scoped_refptr<media::VideoFrame>& frame) {
 }
 
+void WebMediaPlayerAndroid::ResetStreamTextureProxy() {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+
+  if (stream_id_) {
+    GLES2Interface* gl = stream_texture_factory_->ContextGL();
+    gl->DeleteTextures(1, &texture_id_);
+    texture_id_ = 0;
+    texture_mailbox_ = gpu::Mailbox();
+    stream_id_ = 0;
+  }
+  stream_texture_proxy_.reset();
+  needs_establish_peer_ = !needs_external_surface_ && !is_remote_ &&
+                          !player_manager_->IsInFullscreen(frame_) &&
+                          hasVideo();
+
+  TryCreateStreamTextureProxyIfNeeded();
+  if (needs_establish_peer_ && is_playing_)
+    EstablishSurfaceTexturePeer();
+}
+
 void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   // Already created.
@@ -1212,14 +1229,19 @@
   if (!stream_texture_factory_)
     return;
 
+  // Not needed for hole punching.
+  if (!needs_establish_peer_)
+    return;
+
   stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
-  if (needs_establish_peer_ && stream_texture_proxy_) {
+  if (stream_texture_proxy_) {
     DoCreateStreamTexture();
     ReallocateVideoFrame();
+    if (video_frame_provider_client_) {
+      stream_texture_proxy_->BindToLoop(
+          stream_id_, video_frame_provider_client_, compositor_loop_);
+    }
   }
-
-  if (stream_texture_proxy_ && video_frame_provider_client_)
-    stream_texture_proxy_->SetClient(video_frame_provider_client_);
 }
 
 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index dcb63c7..6ca7296 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -66,7 +66,8 @@
 // player.
 class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
                               public cc::VideoFrameProvider,
-                              public RenderFrameObserver {
+                              public RenderFrameObserver,
+                              public StreamTextureFactoryContextObserver {
  public:
   // Construct a WebMediaPlayerAndroid object. This class communicates with the
   // MediaPlayerAndroid object in the browser process through |proxy|.
@@ -191,6 +192,9 @@
   void OnMediaPlayerPause();
   void OnRequestFullscreen();
 
+  // StreamTextureFactoryContextObserver implementation.
+  virtual void ResetStreamTextureProxy() OVERRIDE;
+
   // Called when the player is released.
   virtual void OnPlayerReleased();
 
@@ -398,17 +402,18 @@
   // Whether media player needs to re-establish the surface texture peer.
   bool needs_establish_peer_;
 
-  // Whether |stream_texture_proxy_| is initialized.
-  bool stream_texture_proxy_initialized_;
-
   // Whether the video size info is available.
   bool has_size_info_;
 
+  const scoped_refptr<base::MessageLoopProxy> compositor_loop_;
+
   // Object for allocating stream textures.
   scoped_refptr<StreamTextureFactory> stream_texture_factory_;
 
   // Object for calling back the compositor thread to repaint the video when a
   // frame available. It should be initialized on the compositor thread.
+  // Accessed on main thread and on compositor thread when main thread is
+  // blocked.
   ScopedStreamTextureProxy stream_texture_proxy_;
 
   // Whether media player needs external surface.
@@ -417,6 +422,8 @@
 
   // A pointer back to the compositor to inform it about state changes. This is
   // not NULL while the compositor is actively using this webmediaplayer.
+  // Accessed on main thread and on compositor thread when main thread is
+  // blocked.
   cc::VideoFrameProvider::Client* video_frame_provider_client_;
 
   scoped_ptr<WebLayerImpl> video_weblayer_;