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