• 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   // Protects access to |client_| and |loop_|.
47   base::Lock lock_;
48   cc::VideoFrameProvider::Client* client_;
49   scoped_refptr<base::MessageLoopProxy> loop_;
50 
51   // Accessed on the |loop_| thread only.
52   base::Closure callback_;
53   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
54       context_provider_;
55   scoped_refptr<gfx::SurfaceTexture> surface_texture_;
56   float current_matrix_[16];
57   bool has_updated_;
58 
59   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl);
60 };
61 
StreamTextureProxyImpl(StreamTextureFactorySynchronousImpl::ContextProvider * provider)62 StreamTextureProxyImpl::StreamTextureProxyImpl(
63     StreamTextureFactorySynchronousImpl::ContextProvider* provider)
64     : client_(NULL), context_provider_(provider), has_updated_(false) {
65   std::fill(current_matrix_, current_matrix_ + 16, 0);
66 }
67 
~StreamTextureProxyImpl()68 StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
69 
Release()70 void StreamTextureProxyImpl::Release() {
71   {
72     // Cannot call into |client_| anymore (from any thread) after returning
73     // from here.
74     base::AutoLock lock(lock_);
75     client_ = NULL;
76   }
77   // Release is analogous to the destructor, so there should be no more external
78   // calls to this object in Release. Therefore there is no need to acquire the
79   // lock to access |loop_|.
80   if (!loop_.get() || loop_->BelongsToCurrentThread() ||
81       !loop_->DeleteSoon(FROM_HERE, this)) {
82     delete this;
83   }
84 }
85 
BindToLoop(int32 stream_id,cc::VideoFrameProvider::Client * client,scoped_refptr<base::MessageLoopProxy> loop)86 void StreamTextureProxyImpl::BindToLoop(
87     int32 stream_id,
88     cc::VideoFrameProvider::Client* client,
89     scoped_refptr<base::MessageLoopProxy> loop) {
90   DCHECK(loop);
91 
92   {
93     base::AutoLock lock(lock_);
94     DCHECK(!loop_ || (loop == loop_));
95     loop_ = loop;
96     client_ = client;
97   }
98 
99   if (loop->BelongsToCurrentThread()) {
100     BindOnThread(stream_id);
101     return;
102   }
103   // Unretained is safe here only because the object is deleted on |loop_|
104   // thread.
105   loop->PostTask(FROM_HERE,
106                  base::Bind(&StreamTextureProxyImpl::BindOnThread,
107                             base::Unretained(this),
108                             stream_id));
109 }
110 
BindOnThread(int32 stream_id)111 void StreamTextureProxyImpl::BindOnThread(int32 stream_id) {
112   surface_texture_ = context_provider_->GetSurfaceTexture(stream_id);
113   if (!surface_texture_) {
114     LOG(ERROR) << "Failed to get SurfaceTexture for stream.";
115     return;
116   }
117 
118   callback_ =
119       base::Bind(&StreamTextureProxyImpl::OnFrameAvailable, AsWeakPtr());
120   surface_texture_->SetFrameAvailableCallback(callback_);
121 }
122 
OnFrameAvailable()123 void StreamTextureProxyImpl::OnFrameAvailable() {
124   // GetTransformMatrix only returns something valid after both is true:
125   // - OnFrameAvailable was called
126   // - we called UpdateTexImage
127   if (has_updated_) {
128     float matrix[16];
129     surface_texture_->GetTransformMatrix(matrix);
130 
131     if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) {
132       memcpy(current_matrix_, matrix, sizeof(matrix));
133 
134       base::AutoLock lock(lock_);
135       if (client_)
136         client_->DidUpdateMatrix(current_matrix_);
137     }
138   }
139   // OnFrameAvailable being called a second time implies that we called
140   // updateTexImage since after we received the first frame.
141   has_updated_ = true;
142 
143   base::AutoLock lock(lock_);
144   if (client_)
145     client_->DidReceiveFrame();
146 }
147 
148 }  // namespace
149 
150 // static
151 scoped_refptr<StreamTextureFactorySynchronousImpl>
Create(const CreateContextProviderCallback & try_create_callback,int frame_id)152 StreamTextureFactorySynchronousImpl::Create(
153     const CreateContextProviderCallback& try_create_callback,
154     int frame_id) {
155   return new StreamTextureFactorySynchronousImpl(try_create_callback, frame_id);
156 }
157 
StreamTextureFactorySynchronousImpl(const CreateContextProviderCallback & try_create_callback,int frame_id)158 StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl(
159     const CreateContextProviderCallback& try_create_callback,
160     int frame_id)
161     : create_context_provider_callback_(try_create_callback),
162       context_provider_(create_context_provider_callback_.Run()),
163       frame_id_(frame_id),
164       observer_(NULL) {}
165 
~StreamTextureFactorySynchronousImpl()166 StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {}
167 
CreateProxy()168 StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() {
169   bool had_proxy = !!context_provider_;
170   if (!had_proxy)
171     context_provider_ = create_context_provider_callback_.Run();
172 
173   if (!context_provider_)
174     return NULL;
175 
176   if (observer_ && !had_proxy)
177     context_provider_->AddObserver(observer_);
178   return new StreamTextureProxyImpl(context_provider_);
179 }
180 
EstablishPeer(int32 stream_id,int player_id)181 void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id,
182                                                         int player_id) {
183   DCHECK(context_provider_);
184   scoped_refptr<gfx::SurfaceTexture> surface_texture =
185       context_provider_->GetSurfaceTexture(stream_id);
186   if (surface_texture) {
187     SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
188         base::Process::Current().handle(),
189         surface_texture,
190         frame_id_,
191         player_id);
192   }
193 }
194 
CreateStreamTexture(unsigned texture_target,unsigned * texture_id,gpu::Mailbox * texture_mailbox)195 unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture(
196     unsigned texture_target,
197     unsigned* texture_id,
198     gpu::Mailbox* texture_mailbox) {
199   DCHECK(context_provider_);
200   unsigned stream_id = 0;
201   GLES2Interface* gl = context_provider_->ContextGL();
202   gl->GenTextures(1, texture_id);
203   stream_id = gl->CreateStreamTextureCHROMIUM(*texture_id);
204 
205   gl->GenMailboxCHROMIUM(texture_mailbox->name);
206   gl->ProduceTextureDirectCHROMIUM(
207       *texture_id, texture_target, texture_mailbox->name);
208   return stream_id;
209 }
210 
SetStreamTextureSize(int32 stream_id,const gfx::Size & size)211 void StreamTextureFactorySynchronousImpl::SetStreamTextureSize(
212     int32 stream_id,
213     const gfx::Size& size) {}
214 
ContextGL()215 gpu::gles2::GLES2Interface* StreamTextureFactorySynchronousImpl::ContextGL() {
216   DCHECK(context_provider_);
217   return context_provider_->ContextGL();
218 }
219 
AddObserver(StreamTextureFactoryContextObserver * obs)220 void StreamTextureFactorySynchronousImpl::AddObserver(
221     StreamTextureFactoryContextObserver* obs) {
222   DCHECK(!observer_);
223   observer_ = obs;
224   if (context_provider_)
225     context_provider_->AddObserver(obs);
226 }
227 
RemoveObserver(StreamTextureFactoryContextObserver * obs)228 void StreamTextureFactorySynchronousImpl::RemoveObserver(
229     StreamTextureFactoryContextObserver* obs) {
230   DCHECK_EQ(observer_, obs);
231   observer_ = NULL;
232   if (context_provider_)
233     context_provider_->RemoveObserver(obs);
234 }
235 
236 }  // namespace content
237