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_impl.h"
6
7#include "cc/output/context_provider.h"
8#include "content/common/gpu/client/gpu_channel_host.h"
9#include "content/common/gpu/gpu_messages.h"
10#include "content/renderer/gpu/stream_texture_host_android.h"
11#include "gpu/command_buffer/client/gles2_interface.h"
12#include "ui/gfx/size.h"
13
14namespace content {
15
16namespace {
17
18class StreamTextureProxyImpl : public StreamTextureProxy,
19                               public StreamTextureHost::Listener {
20 public:
21  explicit StreamTextureProxyImpl(StreamTextureHost* host);
22  virtual ~StreamTextureProxyImpl();
23
24  // StreamTextureProxy implementation:
25  virtual void BindToLoop(int32 stream_id,
26                          cc::VideoFrameProvider::Client* client,
27                          scoped_refptr<base::MessageLoopProxy> loop) OVERRIDE;
28  virtual void Release() OVERRIDE;
29
30  // StreamTextureHost::Listener implementation:
31  virtual void OnFrameAvailable() OVERRIDE;
32  virtual void OnMatrixChanged(const float matrix[16]) OVERRIDE;
33
34 private:
35  void BindOnThread(int32 stream_id);
36
37  const scoped_ptr<StreamTextureHost> host_;
38
39  // Protects access to |client_| and |loop_|.
40  base::Lock lock_;
41  cc::VideoFrameProvider::Client* client_;
42  scoped_refptr<base::MessageLoopProxy> loop_;
43
44  DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl);
45};
46
47StreamTextureProxyImpl::StreamTextureProxyImpl(StreamTextureHost* host)
48    : host_(host), client_(NULL) {}
49
50StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
51
52void StreamTextureProxyImpl::Release() {
53  {
54    // Cannot call into |client_| anymore (from any thread) after returning
55    // from here.
56    base::AutoLock lock(lock_);
57    client_ = NULL;
58  }
59  // Release is analogous to the destructor, so there should be no more external
60  // calls to this object in Release. Therefore there is no need to acquire the
61  // lock to access |loop_|.
62  if (!loop_.get() || loop_->BelongsToCurrentThread() ||
63      !loop_->DeleteSoon(FROM_HERE, this)) {
64    delete this;
65  }
66}
67
68void StreamTextureProxyImpl::BindToLoop(
69    int32 stream_id,
70    cc::VideoFrameProvider::Client* client,
71    scoped_refptr<base::MessageLoopProxy> loop) {
72  DCHECK(loop);
73
74  {
75    base::AutoLock lock(lock_);
76    DCHECK(!loop_ || (loop == loop_));
77    loop_ = loop;
78    client_ = client;
79  }
80
81  if (loop->BelongsToCurrentThread()) {
82    BindOnThread(stream_id);
83    return;
84  }
85  // Unretained is safe here only because the object is deleted on |loop_|
86  // thread.
87  loop->PostTask(FROM_HERE,
88                 base::Bind(&StreamTextureProxyImpl::BindOnThread,
89                            base::Unretained(this),
90                            stream_id));
91}
92
93void StreamTextureProxyImpl::BindOnThread(int32 stream_id) {
94  host_->BindToCurrentThread(stream_id, this);
95}
96
97void StreamTextureProxyImpl::OnFrameAvailable() {
98  base::AutoLock lock(lock_);
99  if (client_)
100    client_->DidReceiveFrame();
101}
102
103void StreamTextureProxyImpl::OnMatrixChanged(const float matrix[16]) {
104  base::AutoLock lock(lock_);
105  if (client_)
106    client_->DidUpdateMatrix(matrix);
107}
108
109}  // namespace
110
111// static
112scoped_refptr<StreamTextureFactoryImpl> StreamTextureFactoryImpl::Create(
113    const scoped_refptr<cc::ContextProvider>& context_provider,
114    GpuChannelHost* channel,
115    int frame_id) {
116  return new StreamTextureFactoryImpl(context_provider, channel, frame_id);
117}
118
119StreamTextureFactoryImpl::StreamTextureFactoryImpl(
120    const scoped_refptr<cc::ContextProvider>& context_provider,
121    GpuChannelHost* channel,
122    int frame_id)
123    : context_provider_(context_provider),
124      channel_(channel),
125      frame_id_(frame_id) {
126  DCHECK(channel);
127}
128
129StreamTextureFactoryImpl::~StreamTextureFactoryImpl() {}
130
131StreamTextureProxy* StreamTextureFactoryImpl::CreateProxy() {
132  DCHECK(channel_.get());
133  StreamTextureHost* host = new StreamTextureHost(channel_.get());
134  return new StreamTextureProxyImpl(host);
135}
136
137void StreamTextureFactoryImpl::EstablishPeer(int32 stream_id, int player_id) {
138  DCHECK(channel_.get());
139  channel_->Send(
140      new GpuStreamTextureMsg_EstablishPeer(stream_id, frame_id_, player_id));
141}
142
143unsigned StreamTextureFactoryImpl::CreateStreamTexture(
144    unsigned texture_target,
145    unsigned* texture_id,
146    gpu::Mailbox* texture_mailbox) {
147  GLuint stream_id = 0;
148  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
149  gl->GenTextures(1, texture_id);
150
151  stream_id = gl->CreateStreamTextureCHROMIUM(*texture_id);
152
153  gl->GenMailboxCHROMIUM(texture_mailbox->name);
154  gl->ProduceTextureDirectCHROMIUM(
155      *texture_id, texture_target, texture_mailbox->name);
156  return stream_id;
157}
158
159void StreamTextureFactoryImpl::SetStreamTextureSize(int32 stream_id,
160                                                    const gfx::Size& size) {
161  channel_->Send(new GpuStreamTextureMsg_SetSize(stream_id, size));
162}
163
164gpu::gles2::GLES2Interface* StreamTextureFactoryImpl::ContextGL() {
165  return context_provider_->ContextGL();
166}
167
168void StreamTextureFactoryImpl::AddObserver(
169    StreamTextureFactoryContextObserver* obs) {
170}
171
172void StreamTextureFactoryImpl::RemoveObserver(
173    StreamTextureFactoryContextObserver* obs) {
174}
175
176}  // namespace content
177