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