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