• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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 "cc/layers/video_layer_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "cc/layers/video_frame_provider_client_impl.h"
10 #include "cc/quads/io_surface_draw_quad.h"
11 #include "cc/quads/stream_video_draw_quad.h"
12 #include "cc/quads/texture_draw_quad.h"
13 #include "cc/quads/yuv_video_draw_quad.h"
14 #include "cc/resources/resource_provider.h"
15 #include "cc/resources/single_release_callback_impl.h"
16 #include "cc/trees/layer_tree_impl.h"
17 #include "cc/trees/occlusion_tracker.h"
18 #include "cc/trees/proxy.h"
19 #include "media/base/video_frame.h"
20 
21 #if defined(VIDEO_HOLE)
22 #include "cc/quads/solid_color_draw_quad.h"
23 #endif  // defined(VIDEO_HOLE)
24 
25 namespace cc {
26 
27 // static
Create(LayerTreeImpl * tree_impl,int id,VideoFrameProvider * provider,media::VideoRotation video_rotation)28 scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create(
29     LayerTreeImpl* tree_impl,
30     int id,
31     VideoFrameProvider* provider,
32     media::VideoRotation video_rotation) {
33   scoped_ptr<VideoLayerImpl> layer(
34       new VideoLayerImpl(tree_impl, id, video_rotation));
35   layer->SetProviderClientImpl(VideoFrameProviderClientImpl::Create(provider));
36   DCHECK(tree_impl->proxy()->IsImplThread());
37   DCHECK(tree_impl->proxy()->IsMainThreadBlocked());
38   return layer.Pass();
39 }
40 
VideoLayerImpl(LayerTreeImpl * tree_impl,int id,media::VideoRotation video_rotation)41 VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl,
42                                int id,
43                                media::VideoRotation video_rotation)
44     : LayerImpl(tree_impl, id), frame_(NULL), video_rotation_(video_rotation) {
45 }
46 
~VideoLayerImpl()47 VideoLayerImpl::~VideoLayerImpl() {
48   if (!provider_client_impl_->Stopped()) {
49     // In impl side painting, we may have a pending and active layer
50     // associated with the video provider at the same time. Both have a ref
51     // on the VideoFrameProviderClientImpl, but we stop when the first
52     // LayerImpl (the one on the pending tree) is destroyed since we know
53     // the main thread is blocked for this commit.
54     DCHECK(layer_tree_impl()->proxy()->IsImplThread());
55     DCHECK(layer_tree_impl()->proxy()->IsMainThreadBlocked());
56     provider_client_impl_->Stop();
57   }
58 }
59 
CreateLayerImpl(LayerTreeImpl * tree_impl)60 scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl(
61     LayerTreeImpl* tree_impl) {
62   VideoLayerImpl* impl = new VideoLayerImpl(tree_impl, id(), video_rotation_);
63   return scoped_ptr<LayerImpl>(impl);
64 }
65 
PushPropertiesTo(LayerImpl * layer)66 void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) {
67   LayerImpl::PushPropertiesTo(layer);
68 
69   VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer);
70   other->SetProviderClientImpl(provider_client_impl_);
71 }
72 
DidBecomeActive()73 void VideoLayerImpl::DidBecomeActive() {
74   provider_client_impl_->set_active_video_layer(this);
75 }
76 
WillDraw(DrawMode draw_mode,ResourceProvider * resource_provider)77 bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
78                               ResourceProvider* resource_provider) {
79   if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
80     return false;
81 
82   // Explicitly acquire and release the provider mutex so it can be held from
83   // WillDraw to DidDraw. Since the compositor thread is in the middle of
84   // drawing, the layer will not be destroyed before DidDraw is called.
85   // Therefore, the only thing that will prevent this lock from being released
86   // is the GPU process locking it. As the GPU process can't cause the
87   // destruction of the provider (calling StopUsingProvider), holding this
88   // lock should not cause a deadlock.
89   frame_ = provider_client_impl_->AcquireLockAndCurrentFrame();
90 
91   if (!frame_.get()) {
92     // Drop any resources used by the updater if there is no frame to display.
93     updater_.reset();
94 
95     provider_client_impl_->ReleaseLock();
96     return false;
97   }
98 
99   if (!LayerImpl::WillDraw(draw_mode, resource_provider))
100     return false;
101 
102   if (!updater_) {
103     updater_.reset(
104         new VideoResourceUpdater(layer_tree_impl()->context_provider(),
105                                  layer_tree_impl()->resource_provider()));
106   }
107 
108   VideoFrameExternalResources external_resources =
109       updater_->CreateExternalResourcesFromVideoFrame(frame_);
110   frame_resource_type_ = external_resources.type;
111 
112   if (external_resources.type ==
113       VideoFrameExternalResources::SOFTWARE_RESOURCE) {
114     software_resources_ = external_resources.software_resources;
115     software_release_callback_ =
116         external_resources.software_release_callback;
117     return true;
118   }
119 
120   DCHECK_EQ(external_resources.mailboxes.size(),
121             external_resources.release_callbacks.size());
122   for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
123     unsigned resource_id = resource_provider->CreateResourceFromTextureMailbox(
124         external_resources.mailboxes[i],
125         SingleReleaseCallbackImpl::Create(
126             external_resources.release_callbacks[i]));
127     frame_resources_.push_back(resource_id);
128   }
129 
130   return true;
131 }
132 
AppendQuads(RenderPass * render_pass,const OcclusionTracker<LayerImpl> & occlusion_tracker,AppendQuadsData * append_quads_data)133 void VideoLayerImpl::AppendQuads(
134     RenderPass* render_pass,
135     const OcclusionTracker<LayerImpl>& occlusion_tracker,
136     AppendQuadsData* append_quads_data) {
137   DCHECK(frame_.get());
138 
139   gfx::Transform transform = draw_transform();
140   gfx::Size rotated_size = content_bounds();
141 
142   switch (video_rotation_) {
143     case media::VIDEO_ROTATION_90:
144       rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
145       transform.Rotate(90.0);
146       transform.Translate(0.0, -rotated_size.height());
147       break;
148     case media::VIDEO_ROTATION_180:
149       transform.Rotate(180.0);
150       transform.Translate(-rotated_size.width(), -rotated_size.height());
151       break;
152     case media::VIDEO_ROTATION_270:
153       rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
154       transform.Rotate(270.0);
155       transform.Translate(-rotated_size.width(), 0);
156     case media::VIDEO_ROTATION_0:
157       break;
158   }
159 
160   SharedQuadState* shared_quad_state =
161       render_pass->CreateAndAppendSharedQuadState();
162   shared_quad_state->SetAll(transform,
163                             rotated_size,
164                             visible_content_rect(),
165                             clip_rect(),
166                             is_clipped(),
167                             draw_opacity(),
168                             blend_mode(),
169                             sorting_context_id());
170 
171   AppendDebugBorderQuad(
172       render_pass, rotated_size, shared_quad_state, append_quads_data);
173 
174   gfx::Rect quad_rect(rotated_size);
175   gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
176   gfx::Rect visible_rect = frame_->visible_rect();
177   gfx::Size coded_size = frame_->coded_size();
178 
179   gfx::Rect visible_quad_rect =
180       occlusion_tracker.GetCurrentOcclusionForLayer(transform)
181           .GetUnoccludedContentRect(quad_rect);
182   if (visible_quad_rect.IsEmpty())
183     return;
184 
185   // Pixels for macroblocked formats.
186   const float tex_width_scale =
187       static_cast<float>(visible_rect.width()) / coded_size.width();
188   const float tex_height_scale =
189       static_cast<float>(visible_rect.height()) / coded_size.height();
190   const float tex_x_offset =
191       static_cast<float>(visible_rect.x()) / coded_size.width();
192   const float tex_y_offset =
193       static_cast<float>(visible_rect.y()) / coded_size.height();
194 
195   switch (frame_resource_type_) {
196     // TODO(danakj): Remove this, hide it in the hardware path.
197     case VideoFrameExternalResources::SOFTWARE_RESOURCE: {
198       DCHECK_EQ(frame_resources_.size(), 0u);
199       DCHECK_EQ(software_resources_.size(), 1u);
200       if (software_resources_.size() < 1u)
201         break;
202       bool premultiplied_alpha = true;
203       gfx::PointF uv_top_left(0.f, 0.f);
204       gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
205       float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
206       bool flipped = false;
207       TextureDrawQuad* texture_quad =
208           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
209       texture_quad->SetNew(shared_quad_state,
210                            quad_rect,
211                            opaque_rect,
212                            visible_quad_rect,
213                            software_resources_[0],
214                            premultiplied_alpha,
215                            uv_top_left,
216                            uv_bottom_right,
217                            SK_ColorTRANSPARENT,
218                            opacity,
219                            flipped);
220       break;
221     }
222     case VideoFrameExternalResources::YUV_RESOURCE: {
223       DCHECK_GE(frame_resources_.size(), 3u);
224       if (frame_resources_.size() < 3u)
225         break;
226       YUVVideoDrawQuad::ColorSpace color_space =
227           frame_->format() == media::VideoFrame::YV12J
228               ? YUVVideoDrawQuad::REC_601_JPEG
229               : YUVVideoDrawQuad::REC_601;
230       gfx::RectF tex_coord_rect(
231           tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
232       YUVVideoDrawQuad* yuv_video_quad =
233           render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
234       yuv_video_quad->SetNew(
235           shared_quad_state,
236           quad_rect,
237           opaque_rect,
238           visible_quad_rect,
239           tex_coord_rect,
240           frame_resources_[0],
241           frame_resources_[1],
242           frame_resources_[2],
243           frame_resources_.size() > 3 ? frame_resources_[3] : 0,
244           color_space);
245       break;
246     }
247     case VideoFrameExternalResources::RGB_RESOURCE: {
248       DCHECK_EQ(frame_resources_.size(), 1u);
249       if (frame_resources_.size() < 1u)
250         break;
251       bool premultiplied_alpha = true;
252       gfx::PointF uv_top_left(0.f, 0.f);
253       gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
254       float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
255       bool flipped = false;
256       TextureDrawQuad* texture_quad =
257           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
258       texture_quad->SetNew(shared_quad_state,
259                            quad_rect,
260                            opaque_rect,
261                            visible_quad_rect,
262                            frame_resources_[0],
263                            premultiplied_alpha,
264                            uv_top_left,
265                            uv_bottom_right,
266                            SK_ColorTRANSPARENT,
267                            opacity,
268                            flipped);
269       break;
270     }
271     case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
272       DCHECK_EQ(frame_resources_.size(), 1u);
273       if (frame_resources_.size() < 1u)
274         break;
275       gfx::Transform scale;
276       scale.Scale(tex_width_scale, tex_height_scale);
277       StreamVideoDrawQuad* stream_video_quad =
278           render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
279       stream_video_quad->SetNew(
280           shared_quad_state,
281           quad_rect,
282           opaque_rect,
283           visible_quad_rect,
284           frame_resources_[0],
285           scale * provider_client_impl_->stream_texture_matrix());
286       break;
287     }
288     case VideoFrameExternalResources::IO_SURFACE: {
289       DCHECK_EQ(frame_resources_.size(), 1u);
290       if (frame_resources_.size() < 1u)
291         break;
292       IOSurfaceDrawQuad* io_surface_quad =
293           render_pass->CreateAndAppendDrawQuad<IOSurfaceDrawQuad>();
294       io_surface_quad->SetNew(shared_quad_state,
295                               quad_rect,
296                               opaque_rect,
297                               visible_quad_rect,
298                               visible_rect.size(),
299                               frame_resources_[0],
300                               IOSurfaceDrawQuad::UNFLIPPED);
301       break;
302     }
303 #if defined(VIDEO_HOLE)
304     // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
305     // maintained by the general compositor team. Please contact the following
306     // people instead:
307     //
308     // wonsik@chromium.org
309     // ycheo@chromium.org
310     case VideoFrameExternalResources::HOLE: {
311       DCHECK_EQ(frame_resources_.size(), 0u);
312       SolidColorDrawQuad* solid_color_draw_quad =
313           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
314 
315       // Create a solid color quad with transparent black and force no
316       // blending / no anti-aliasing.
317       gfx::Rect opaque_rect = quad_rect;
318       solid_color_draw_quad->SetAll(shared_quad_state,
319                                     quad_rect,
320                                     opaque_rect,
321                                     visible_quad_rect,
322                                     false,
323                                     SK_ColorTRANSPARENT,
324                                     true);
325       break;
326     }
327 #endif  // defined(VIDEO_HOLE)
328     case VideoFrameExternalResources::NONE:
329       NOTIMPLEMENTED();
330       break;
331   }
332 }
333 
DidDraw(ResourceProvider * resource_provider)334 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
335   LayerImpl::DidDraw(resource_provider);
336 
337   DCHECK(frame_.get());
338 
339   if (frame_resource_type_ ==
340       VideoFrameExternalResources::SOFTWARE_RESOURCE) {
341     for (size_t i = 0; i < software_resources_.size(); ++i) {
342       software_release_callback_.Run(
343           0, false, layer_tree_impl()->BlockingMainThreadTaskRunner());
344     }
345 
346     software_resources_.clear();
347     software_release_callback_.Reset();
348   } else {
349     for (size_t i = 0; i < frame_resources_.size(); ++i)
350       resource_provider->DeleteResource(frame_resources_[i]);
351     frame_resources_.clear();
352   }
353 
354   provider_client_impl_->PutCurrentFrame(frame_);
355   frame_ = NULL;
356 
357   provider_client_impl_->ReleaseLock();
358 }
359 
ReleaseResources()360 void VideoLayerImpl::ReleaseResources() {
361   updater_.reset();
362 }
363 
SetNeedsRedraw()364 void VideoLayerImpl::SetNeedsRedraw() {
365   SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
366   layer_tree_impl()->SetNeedsRedraw();
367 }
368 
SetProviderClientImpl(scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl)369 void VideoLayerImpl::SetProviderClientImpl(
370     scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) {
371   provider_client_impl_ = provider_client_impl;
372 }
373 
LayerTypeAsString() const374 const char* VideoLayerImpl::LayerTypeAsString() const {
375   return "cc::VideoLayerImpl";
376 }
377 
378 }  // namespace cc
379