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 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 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 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 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 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 73 void VideoLayerImpl::DidBecomeActive() { 74 provider_client_impl_->set_active_video_layer(this); 75 } 76 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 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 (at) chromium.org 309 // ycheo (at) 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 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 360 void VideoLayerImpl::ReleaseResources() { 361 updater_.reset(); 362 } 363 364 void VideoLayerImpl::SetNeedsRedraw() { 365 SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds()))); 366 layer_tree_impl()->SetNeedsRedraw(); 367 } 368 369 void VideoLayerImpl::SetProviderClientImpl( 370 scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) { 371 provider_client_impl_ = provider_client_impl; 372 } 373 374 const char* VideoLayerImpl::LayerTypeAsString() const { 375 return "cc::VideoLayerImpl"; 376 } 377 378 } // namespace cc 379