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