• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/renderer/media/android/stream_texture_factory_synchronous_impl.h"
6 
7 #include <algorithm>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/location.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/process/process.h"
15 #include "base/synchronization/lock.h"
16 #include "cc/output/context_provider.h"
17 #include "content/common/android/surface_texture_peer.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "gpu/command_buffer/client/gles2_interface.h"
20 #include "ui/gl/android/surface_texture.h"
21 
22 using gpu::gles2::GLES2Interface;
23 
24 namespace content {
25 
26 namespace {
27 
28 class StreamTextureProxyImpl
29     : public StreamTextureProxy,
30       public base::SupportsWeakPtr<StreamTextureProxyImpl> {
31  public:
32   explicit StreamTextureProxyImpl(
33       StreamTextureFactorySynchronousImpl::ContextProvider* provider);
34   virtual ~StreamTextureProxyImpl();
35 
36   // StreamTextureProxy implementation:
37   virtual void BindToLoop(int32 stream_id,
38                           cc::VideoFrameProvider::Client* client,
39                           scoped_refptr<base::MessageLoopProxy> loop) OVERRIDE;
40   virtual void Release() OVERRIDE;
41 
42  private:
43   void BindOnThread(int32 stream_id);
44   void OnFrameAvailable();
45 
46   base::Lock lock_;
47   cc::VideoFrameProvider::Client* client_;
48   scoped_refptr<base::MessageLoopProxy> loop_;
49 
50   // Accessed on the |loop_| thread only.
51   base::Closure callback_;
52   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
53       context_provider_;
54   scoped_refptr<gfx::SurfaceTexture> surface_texture_;
55   float current_matrix_[16];
56   bool has_updated_;
57 
58   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl);
59 };
60 
StreamTextureProxyImpl(StreamTextureFactorySynchronousImpl::ContextProvider * provider)61 StreamTextureProxyImpl::StreamTextureProxyImpl(
62     StreamTextureFactorySynchronousImpl::ContextProvider* provider)
63     : client_(NULL), context_provider_(provider), has_updated_(false) {
64   std::fill(current_matrix_, current_matrix_ + 16, 0);
65 }
66 
~StreamTextureProxyImpl()67 StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
68 
Release()69 void StreamTextureProxyImpl::Release() {
70   {
71     base::AutoLock lock(lock_);
72     client_ = NULL;
73   }
74   // Assumes this is the last reference to this object. So no need to acquire
75   // lock.
76   if (!loop_.get() || loop_->BelongsToCurrentThread() ||
77       !loop_->DeleteSoon(FROM_HERE, this)) {
78     delete this;
79   }
80 }
81 
BindToLoop(int32 stream_id,cc::VideoFrameProvider::Client * client,scoped_refptr<base::MessageLoopProxy> loop)82 void StreamTextureProxyImpl::BindToLoop(
83     int32 stream_id,
84     cc::VideoFrameProvider::Client* client,
85     scoped_refptr<base::MessageLoopProxy> loop) {
86   DCHECK(loop);
87 
88   {
89     base::AutoLock lock(lock_);
90     DCHECK(!loop_ || (loop == loop_));
91     loop_ = loop;
92     client_ = client;
93   }
94 
95   if (loop->BelongsToCurrentThread()) {
96     BindOnThread(stream_id);
97     return;
98   }
99   // Unretained is safe here only because the object is deleted on |loop_|
100   // thread.
101   loop->PostTask(FROM_HERE,
102                  base::Bind(&StreamTextureProxyImpl::BindOnThread,
103                             base::Unretained(this),
104                             stream_id));
105 }
106 
BindOnThread(int32 stream_id)107 void StreamTextureProxyImpl::BindOnThread(int32 stream_id) {
108   surface_texture_ = context_provider_->GetSurfaceTexture(stream_id);
109   if (!surface_texture_) {
110     LOG(ERROR) << "Failed to get SurfaceTexture for stream.";
111     return;
112   }
113 
114   callback_ =
115       base::Bind(&StreamTextureProxyImpl::OnFrameAvailable, AsWeakPtr());
116   surface_texture_->SetFrameAvailableCallback(callback_);
117 }
118 
OnFrameAvailable()119 void StreamTextureProxyImpl::OnFrameAvailable() {
120   // GetTransformMatrix only returns something valid after both is true:
121   // - OnFrameAvailable was called
122   // - we called UpdateTexImage
123   if (has_updated_) {
124     float matrix[16];
125     surface_texture_->GetTransformMatrix(matrix);
126 
127     if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) {
128       memcpy(current_matrix_, matrix, sizeof(matrix));
129 
130       base::AutoLock lock(lock_);
131       if (client_)
132         client_->DidUpdateMatrix(current_matrix_);
133     }
134   }
135   // OnFrameAvailable being called a second time implies that we called
136   // updateTexImage since after we received the first frame.
137   has_updated_ = true;
138 
139   base::AutoLock lock(lock_);
140   if (client_)
141     client_->DidReceiveFrame();
142 }
143 
144 }  // namespace
145 
146 // static
147 scoped_refptr<StreamTextureFactorySynchronousImpl>
Create(const CreateContextProviderCallback & try_create_callback,int frame_id)148 StreamTextureFactorySynchronousImpl::Create(
149     const CreateContextProviderCallback& try_create_callback,
150     int frame_id) {
151   return new StreamTextureFactorySynchronousImpl(try_create_callback, frame_id);
152 }
153 
StreamTextureFactorySynchronousImpl(const CreateContextProviderCallback & try_create_callback,int frame_id)154 StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl(
155     const CreateContextProviderCallback& try_create_callback,
156     int frame_id)
157     : create_context_provider_callback_(try_create_callback),
158       context_provider_(create_context_provider_callback_.Run()),
159       frame_id_(frame_id),
160       observer_(NULL) {}
161 
~StreamTextureFactorySynchronousImpl()162 StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {}
163 
CreateProxy()164 StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() {
165   if (!context_provider_)
166     context_provider_ = create_context_provider_callback_.Run();
167 
168   if (!context_provider_)
169     return NULL;
170 
171   if (observer_)
172     context_provider_->AddObserver(observer_);
173   return new StreamTextureProxyImpl(context_provider_);
174 }
175 
EstablishPeer(int32 stream_id,int player_id)176 void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id,
177                                                         int player_id) {
178   DCHECK(context_provider_);
179   scoped_refptr<gfx::SurfaceTexture> surface_texture =
180       context_provider_->GetSurfaceTexture(stream_id);
181   if (surface_texture) {
182     SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
183         base::Process::Current().handle(),
184         surface_texture,
185         frame_id_,
186         player_id);
187   }
188 }
189 
CreateStreamTexture(unsigned texture_target,unsigned * texture_id,gpu::Mailbox * texture_mailbox)190 unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture(
191     unsigned texture_target,
192     unsigned* texture_id,
193     gpu::Mailbox* texture_mailbox) {
194   DCHECK(context_provider_);
195   unsigned stream_id = 0;
196   GLES2Interface* gl = context_provider_->ContextGL();
197   gl->GenTextures(1, texture_id);
198   stream_id = gl->CreateStreamTextureCHROMIUM(*texture_id);
199 
200   gl->GenMailboxCHROMIUM(texture_mailbox->name);
201   gl->BindTexture(texture_target, *texture_id);
202   gl->ProduceTextureCHROMIUM(texture_target, texture_mailbox->name);
203   return stream_id;
204 }
205 
SetStreamTextureSize(int32 stream_id,const gfx::Size & size)206 void StreamTextureFactorySynchronousImpl::SetStreamTextureSize(
207     int32 stream_id,
208     const gfx::Size& size) {}
209 
ContextGL()210 gpu::gles2::GLES2Interface* StreamTextureFactorySynchronousImpl::ContextGL() {
211   DCHECK(context_provider_);
212   return context_provider_->ContextGL();
213 }
214 
AddObserver(StreamTextureFactoryContextObserver * obs)215 void StreamTextureFactorySynchronousImpl::AddObserver(
216     StreamTextureFactoryContextObserver* obs) {
217   DCHECK(!observer_);
218   observer_ = obs;
219   if (context_provider_)
220     context_provider_->AddObserver(obs);
221 }
222 
RemoveObserver(StreamTextureFactoryContextObserver * obs)223 void StreamTextureFactorySynchronousImpl::RemoveObserver(
224     StreamTextureFactoryContextObserver* obs) {
225   DCHECK_EQ(observer_, obs);
226   observer_ = NULL;
227   if (context_provider_)
228     context_provider_->RemoveObserver(obs);
229 }
230 
231 }  // namespace content
232