video_layer_impl.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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 24namespace cc { 25 26// static 27scoped_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 38VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl, int id) 39 : LayerImpl(tree_impl, id), 40 frame_(NULL), 41 hardware_resource_(0) {} 42 43VideoLayerImpl::~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 56scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl( 57 LayerTreeImpl* tree_impl) { 58 return scoped_ptr<LayerImpl>(new VideoLayerImpl(tree_impl, id())); 59} 60 61void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) { 62 LayerImpl::PushPropertiesTo(layer); 63 64 VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer); 65 other->SetProviderClientImpl(provider_client_impl_); 66} 67 68void VideoLayerImpl::DidBecomeActive() { 69 provider_client_impl_->set_active_video_layer(this); 70} 71 72bool 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 LayerImpl::WillDraw(draw_mode, resource_provider); 95 96 if (!updater_) 97 updater_.reset(new VideoResourceUpdater(resource_provider)); 98 99 VideoFrameExternalResources external_resources; 100 if (frame_->format() == media::VideoFrame::NATIVE_TEXTURE) 101 external_resources = updater_->CreateForHardwarePlanes(frame_); 102 else 103 external_resources = updater_->CreateForSoftwarePlanes(frame_); 104 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 if (external_resources.hardware_resource) { 116 hardware_resource_ = external_resources.hardware_resource; 117 hardware_release_callback_ = 118 external_resources.hardware_release_callback; 119 return true; 120 } 121 122 for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) { 123 frame_resources_.push_back( 124 resource_provider->CreateResourceFromTextureMailbox( 125 external_resources.mailboxes[i])); 126 } 127 128 return true; 129} 130 131void VideoLayerImpl::AppendQuads(QuadSink* quad_sink, 132 AppendQuadsData* append_quads_data) { 133 DCHECK(frame_.get()); 134 135 SharedQuadState* shared_quad_state = 136 quad_sink->UseSharedQuadState(CreateSharedQuadState()); 137 AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); 138 139 gfx::Rect quad_rect(content_bounds()); 140 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect()); 141 gfx::Rect visible_rect = frame_->visible_rect(); 142 gfx::Size coded_size = frame_->coded_size(); 143 144 // Pixels for macroblocked formats. 145 float tex_width_scale = 146 static_cast<float>(visible_rect.width()) / coded_size.width(); 147 float tex_height_scale = 148 static_cast<float>(visible_rect.height()) / coded_size.height(); 149 150 switch (frame_resource_type_) { 151 // TODO(danakj): Remove this, hide it in the hardware path. 152 case VideoFrameExternalResources::SOFTWARE_RESOURCE: { 153 DCHECK_EQ(frame_resources_.size(), 0u); 154 DCHECK_EQ(software_resources_.size(), 1u); 155 if (software_resources_.size() < 1u) 156 break; 157 bool premultiplied_alpha = true; 158 gfx::PointF uv_top_left(0.f, 0.f); 159 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); 160 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 161 bool flipped = false; 162 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create(); 163 texture_quad->SetNew(shared_quad_state, 164 quad_rect, 165 opaque_rect, 166 software_resources_[0], 167 premultiplied_alpha, 168 uv_top_left, 169 uv_bottom_right, 170 opacity, 171 flipped); 172 quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data); 173 break; 174 } 175 case VideoFrameExternalResources::YUV_RESOURCE: { 176 DCHECK_GE(frame_resources_.size(), 3u); 177 if (frame_resources_.size() < 3u) 178 break; 179 gfx::SizeF tex_scale(tex_width_scale, tex_height_scale); 180 scoped_ptr<YUVVideoDrawQuad> yuv_video_quad = YUVVideoDrawQuad::Create(); 181 yuv_video_quad->SetNew(shared_quad_state, 182 quad_rect, 183 opaque_rect, 184 tex_scale, 185 frame_resources_[0], 186 frame_resources_[1], 187 frame_resources_[2], 188 frame_resources_.size() > 3 ? 189 frame_resources_[3] : 0); 190 quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>(), append_quads_data); 191 break; 192 } 193 case VideoFrameExternalResources::RGB_RESOURCE: { 194 if (!hardware_resource_) { 195 DCHECK_EQ(frame_resources_.size(), 1u); 196 if (frame_resources_.size() < 1u) 197 break; 198 } 199 bool premultiplied_alpha = true; 200 gfx::PointF uv_top_left(0.f, 0.f); 201 gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale); 202 float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; 203 bool flipped = false; 204 scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create(); 205 texture_quad->SetNew(shared_quad_state, 206 quad_rect, 207 opaque_rect, 208 hardware_resource_ ? hardware_resource_ 209 : frame_resources_[0], 210 premultiplied_alpha, 211 uv_top_left, 212 uv_bottom_right, 213 opacity, 214 flipped); 215 quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data); 216 break; 217 } 218 case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: { 219 if (!hardware_resource_) { 220 DCHECK_EQ(frame_resources_.size(), 1u); 221 if (frame_resources_.size() < 1u) 222 break; 223 } 224 gfx::Transform transform( 225 provider_client_impl_->stream_texture_matrix()); 226 transform.Scale(tex_width_scale, tex_height_scale); 227 scoped_ptr<StreamVideoDrawQuad> stream_video_quad = 228 StreamVideoDrawQuad::Create(); 229 stream_video_quad->SetNew(shared_quad_state, 230 quad_rect, 231 opaque_rect, 232 hardware_resource_ ? hardware_resource_ 233 : frame_resources_[0], 234 transform); 235 quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(), 236 append_quads_data); 237 break; 238 } 239 case VideoFrameExternalResources::IO_SURFACE: { 240 if (!hardware_resource_) { 241 DCHECK_EQ(frame_resources_.size(), 1u); 242 if (frame_resources_.size() < 1u) 243 break; 244 } 245 gfx::Size visible_size(visible_rect.width(), visible_rect.height()); 246 scoped_ptr<IOSurfaceDrawQuad> io_surface_quad = 247 IOSurfaceDrawQuad::Create(); 248 io_surface_quad->SetNew(shared_quad_state, 249 quad_rect, 250 opaque_rect, 251 visible_size, 252 hardware_resource_ ? hardware_resource_ 253 : frame_resources_[0], 254 IOSurfaceDrawQuad::UNFLIPPED); 255 quad_sink->Append(io_surface_quad.PassAs<DrawQuad>(), 256 append_quads_data); 257 break; 258 } 259#if defined(GOOGLE_TV) 260 // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not 261 // maintained by the general compositor team. Please contact the following 262 // people instead: 263 // 264 // wonsik@chromium.org 265 // ycheo@chromium.org 266 case VideoFrameExternalResources::HOLE: { 267 DCHECK_EQ(frame_resources_.size(), 0u); 268 scoped_ptr<SolidColorDrawQuad> solid_color_draw_quad = 269 SolidColorDrawQuad::Create(); 270 271 // Create a solid color quad with transparent black and force no 272 // blending / no anti-aliasing. 273 solid_color_draw_quad->SetAll( 274 shared_quad_state, quad_rect, quad_rect, quad_rect, false, 275 SK_ColorTRANSPARENT, true); 276 quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>(), 277 append_quads_data); 278 break; 279 } 280#endif 281 case VideoFrameExternalResources::NONE: 282 NOTIMPLEMENTED(); 283 break; 284 } 285} 286 287void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) { 288 LayerImpl::DidDraw(resource_provider); 289 290 DCHECK(frame_.get()); 291 292 if (frame_resource_type_ == 293 VideoFrameExternalResources::SOFTWARE_RESOURCE) { 294 for (size_t i = 0; i < software_resources_.size(); ++i) 295 software_release_callback_.Run(0, false); 296 297 software_resources_.clear(); 298 software_release_callback_.Reset(); 299 } else if (hardware_resource_) { 300 hardware_release_callback_.Run(0, false); 301 hardware_resource_ = 0; 302 hardware_release_callback_.Reset(); 303 } else { 304 for (size_t i = 0; i < frame_resources_.size(); ++i) 305 resource_provider->DeleteResource(frame_resources_[i]); 306 frame_resources_.clear(); 307 } 308 309 provider_client_impl_->PutCurrentFrame(frame_); 310 frame_ = NULL; 311 312 provider_client_impl_->ReleaseLock(); 313} 314 315void VideoLayerImpl::DidLoseOutputSurface() { 316 updater_.reset(); 317} 318 319void VideoLayerImpl::SetNeedsRedraw() { 320 set_update_rect(gfx::UnionRects(update_rect(), gfx::RectF(bounds()))); 321 layer_tree_impl()->SetNeedsRedraw(); 322} 323 324void VideoLayerImpl::SetProviderClientImpl( 325 scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) { 326 provider_client_impl_ = provider_client_impl; 327} 328 329const char* VideoLayerImpl::LayerTypeAsString() const { 330 return "cc::VideoLayerImpl"; 331} 332 333} // namespace cc 334