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 = 132 quad_sink->UseSharedQuadState(CreateSharedQuadState()); 133 AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); 134 135 gfx::Rect quad_rect(content_bounds()); 136 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect()); 137 gfx::Rect visible_rect = frame_->visible_rect(); 138 gfx::Size coded_size = frame_->coded_size(); 139 140 // Pixels for macroblocked formats. 141 float tex_width_scale = 142 static_cast<float>(visible_rect.width()) / coded_size.width(); 143 float tex_height_scale = 144 static_cast<float>(visible_rect.height()) / coded_size.height(); 145 146 switch (frame_resource_type_) { 147 // TODO(danakj): Remove this, hide it in the hardware path. 148 case VideoFrameExternalResources::SOFTWARE_RESOURCE: { 149 DCHECK_EQ(frame_resources_.size(), 0u); 150 DCHECK_EQ(software_resources_.size(), 1u); 151 if (software_resources_.size() < 1u) 152 break; 153 bool premultiplied_alpha = true; 154 gfx::PointF uv_top_left(0.f, 0.f); 155 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); 156 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 157 bool flipped = false; 158 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create(); 159 texture_quad->SetNew(shared_quad_state, 160 quad_rect, 161 opaque_rect, 162 software_resources_[0], 163 premultiplied_alpha, 164 uv_top_left, 165 uv_bottom_right, 166 SK_ColorTRANSPARENT, 167 opacity, 168 flipped); 169 quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data); 170 break; 171 } 172 case VideoFrameExternalResources::YUV_RESOURCE: { 173 DCHECK_GE(frame_resources_.size(), 3u); 174 if (frame_resources_.size() < 3u) 175 break; 176 gfx::SizeF tex_scale(tex_width_scale, tex_height_scale); 177 scoped_ptr<YUVVideoDrawQuad> yuv_video_quad = YUVVideoDrawQuad::Create(); 178 yuv_video_quad->SetNew(shared_quad_state, 179 quad_rect, 180 opaque_rect, 181 tex_scale, 182 frame_resources_[0], 183 frame_resources_[1], 184 frame_resources_[2], 185 frame_resources_.size() > 3 ? 186 frame_resources_[3] : 0); 187 quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>(), append_quads_data); 188 break; 189 } 190 case VideoFrameExternalResources::RGB_RESOURCE: { 191 DCHECK_EQ(frame_resources_.size(), 1u); 192 if (frame_resources_.size() < 1u) 193 break; 194 bool premultiplied_alpha = true; 195 gfx::PointF uv_top_left(0.f, 0.f); 196 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); 197 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 198 bool flipped = false; 199 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create(); 200 texture_quad->SetNew(shared_quad_state, 201 quad_rect, 202 opaque_rect, 203 frame_resources_[0], 204 premultiplied_alpha, 205 uv_top_left, 206 uv_bottom_right, 207 SK_ColorTRANSPARENT, 208 opacity, 209 flipped); 210 quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data); 211 break; 212 } 213 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: { 214 DCHECK_EQ(frame_resources_.size(), 1u); 215 if (frame_resources_.size() < 1u) 216 break; 217 gfx::Transform scale; 218 scale.Scale(tex_width_scale, tex_height_scale); 219 scoped_ptr<StreamVideoDrawQuad> stream_video_quad = 220 StreamVideoDrawQuad::Create(); 221 stream_video_quad->SetNew( 222 shared_quad_state, 223 quad_rect, 224 opaque_rect, 225 frame_resources_[0], 226 scale * provider_client_impl_->stream_texture_matrix()); 227 quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(), 228 append_quads_data); 229 break; 230 } 231 case VideoFrameExternalResources::IO_SURFACE: { 232 DCHECK_EQ(frame_resources_.size(), 1u); 233 if (frame_resources_.size() < 1u) 234 break; 235 gfx::Size visible_size(visible_rect.width(), visible_rect.height()); 236 scoped_ptr<IOSurfaceDrawQuad> io_surface_quad = 237 IOSurfaceDrawQuad::Create(); 238 io_surface_quad->SetNew(shared_quad_state, 239 quad_rect, 240 opaque_rect, 241 visible_size, 242 frame_resources_[0], 243 IOSurfaceDrawQuad::UNFLIPPED); 244 quad_sink->Append(io_surface_quad.PassAs<DrawQuad>(), 245 append_quads_data); 246 break; 247 } 248 #if defined(VIDEO_HOLE) 249 // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not 250 // maintained by the general compositor team. Please contact the following 251 // people instead: 252 // 253 // wonsik (at) chromium.org 254 // ycheo (at) chromium.org 255 case VideoFrameExternalResources::HOLE: { 256 DCHECK_EQ(frame_resources_.size(), 0u); 257 scoped_ptr<SolidColorDrawQuad> solid_color_draw_quad = 258 SolidColorDrawQuad::Create(); 259 260 // Create a solid color quad with transparent black and force no 261 // blending / no anti-aliasing. 262 solid_color_draw_quad->SetAll( 263 shared_quad_state, quad_rect, quad_rect, quad_rect, false, 264 SK_ColorTRANSPARENT, true); 265 quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>(), 266 append_quads_data); 267 break; 268 } 269 #endif // defined(VIDEO_HOLE) 270 case VideoFrameExternalResources::NONE: 271 NOTIMPLEMENTED(); 272 break; 273 } 274 } 275 276 void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) { 277 LayerImpl::DidDraw(resource_provider); 278 279 DCHECK(frame_.get()); 280 281 if (frame_resource_type_ == 282 VideoFrameExternalResources::SOFTWARE_RESOURCE) { 283 for (size_t i = 0; i < software_resources_.size(); ++i) 284 software_release_callback_.Run(0, false); 285 286 software_resources_.clear(); 287 software_release_callback_.Reset(); 288 } else { 289 for (size_t i = 0; i < frame_resources_.size(); ++i) 290 resource_provider->DeleteResource(frame_resources_[i]); 291 frame_resources_.clear(); 292 } 293 294 provider_client_impl_->PutCurrentFrame(frame_); 295 frame_ = NULL; 296 297 provider_client_impl_->ReleaseLock(); 298 } 299 300 void VideoLayerImpl::DidLoseOutputSurface() { 301 updater_.reset(); 302 } 303 304 void VideoLayerImpl::SetNeedsRedraw() { 305 set_update_rect(gfx::UnionRects(update_rect(), gfx::RectF(bounds()))); 306 layer_tree_impl()->SetNeedsRedraw(); 307 } 308 309 void VideoLayerImpl::SetProviderClientImpl( 310 scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) { 311 provider_client_impl_ = provider_client_impl; 312 } 313 314 const char* VideoLayerImpl::LayerTypeAsString() const { 315 return "cc::VideoLayerImpl"; 316 } 317 318 } // namespace cc 319