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