Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 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/resources/video_resource_updater.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "cc/output/gl_renderer.h" | |
| 9 #include "cc/resources/resource_provider.h" | |
| 10 #include "gpu/GLES2/gl2extchromium.h" | |
| 11 #include "media/base/video_frame.h" | |
| 12 #include "media/filters/skcanvas_video_renderer.h" | |
| 13 #include "third_party/khronos/GLES2/gl2.h" | |
| 14 #include "third_party/khronos/GLES2/gl2ext.h" | |
| 15 #include "ui/gfx/size_conversions.h" | |
| 16 | |
| 17 const unsigned kYUVResourceFormat = GL_LUMINANCE; | |
| 18 const unsigned kRGBResourceFormat = GL_RGBA; | |
| 19 | |
| 20 namespace cc { | |
| 21 | |
| 22 VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {} | |
| 23 | |
| 24 VideoFrameExternalResources::~VideoFrameExternalResources() {} | |
| 25 | |
| 26 VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider) | |
| 27 : resource_provider_(resource_provider) { | |
| 28 } | |
| 29 | |
| 30 VideoResourceUpdater::~VideoResourceUpdater() {} | |
| 31 | |
| 32 bool VideoResourceUpdater::VerifyFrame( | |
| 33 const scoped_refptr<media::VideoFrame>& video_frame) { | |
| 34 // If these fail, we'll have to add logic that handles offset bitmap/texture | |
| 35 // UVs. For now, just expect (0, 0) offset, since all our decoders so far | |
| 36 // don't offset. | |
| 37 DCHECK_EQ(video_frame->visible_rect().x(), 0); | |
| 38 DCHECK_EQ(video_frame->visible_rect().y(), 0); | |
| 39 | |
| 40 switch (video_frame->format()) { | |
| 41 // Acceptable inputs. | |
| 42 case media::VideoFrame::YV12: | |
| 43 case media::VideoFrame::YV16: | |
| 44 case media::VideoFrame::NATIVE_TEXTURE: | |
| 45 #if defined(GOOGLE_TV) | |
| 46 case media::VideoFrame::HOLE: | |
| 47 #endif | |
| 48 return true; | |
| 49 | |
| 50 // Unacceptable inputs. ¯\(°_o)/¯ | |
| 51 case media::VideoFrame::INVALID: | |
| 52 case media::VideoFrame::RGB32: | |
| 53 case media::VideoFrame::EMPTY: | |
| 54 case media::VideoFrame::I420: | |
| 55 break; | |
| 56 } | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 // For frames that we receive in software format, determine the dimensions of | |
| 61 // each plane in the frame. | |
| 62 static gfx::Size SoftwarePlaneDimension( | |
| 63 media::VideoFrame::Format input_frame_format, | |
| 64 gfx::Size coded_size, | |
| 65 GLenum output_resource_format, | |
| 66 int plane_index) { | |
| 67 if (output_resource_format == kYUVResourceFormat) { | |
| 68 if (plane_index == media::VideoFrame::kYPlane) | |
| 69 return coded_size; | |
| 70 | |
| 71 switch (input_frame_format) { | |
| 72 case media::VideoFrame::YV12: | |
| 73 return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 0.5f)); | |
| 74 case media::VideoFrame::YV16: | |
| 75 return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 1.f)); | |
| 76 | |
| 77 case media::VideoFrame::INVALID: | |
| 78 case media::VideoFrame::RGB32: | |
| 79 case media::VideoFrame::EMPTY: | |
| 80 case media::VideoFrame::I420: | |
| 81 case media::VideoFrame::NATIVE_TEXTURE: | |
| 82 #if defined(GOOGLE_TV) | |
| 83 case media::VideoFrame::HOLE: | |
| 84 #endif | |
| 85 NOTREACHED(); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 DCHECK_EQ(output_resource_format, static_cast<unsigned>(kRGBResourceFormat)); | |
| 90 return coded_size; | |
| 91 } | |
| 92 | |
| 93 static void ReleaseResource(base::WeakPtr<ResourceProvider> resource_provider, | |
| 94 ResourceProvider::ResourceId resource_id, | |
| 95 unsigned sync_point) { | |
| 96 if (resource_provider) | |
| 97 resource_provider->DeleteResource(resource_id); | |
| 98 } | |
| 99 | |
| 100 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( | |
| 101 const scoped_refptr<media::VideoFrame>& video_frame) { | |
| 102 if (!VerifyFrame(video_frame)) | |
| 103 return VideoFrameExternalResources(); | |
| 104 | |
| 105 media::VideoFrame::Format input_frame_format = video_frame->format(); | |
| 106 | |
| 107 #if defined(GOOGLE_TV) | |
| 108 if (input_frame_format == media::VideoFrame::HOLE) { | |
| 109 VideoFrameExternalResources external_resources; | |
| 110 external_resources.type = VideoFrameExternalResources::HOLE; | |
| 111 return external_resources; | |
| 112 } | |
| 113 #endif | |
| 114 | |
| 115 // Only YUV software video frames are supported. | |
| 116 DCHECK(input_frame_format == media::VideoFrame::YV12 || | |
| 117 input_frame_format == media::VideoFrame::YV16); | |
| 118 if (input_frame_format != media::VideoFrame::YV12 && | |
| 119 input_frame_format != media::VideoFrame::YV16) | |
| 120 return VideoFrameExternalResources(); | |
| 121 | |
| 122 bool software_compositor = !resource_provider_->GraphicsContext3D(); | |
| 123 | |
| 124 GLenum output_resource_format = kYUVResourceFormat; | |
| 125 size_t output_plane_count = 3; | |
| 126 | |
| 127 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB | |
| 128 // conversion here. That involves an extra copy of each frame to a bitmap. | |
| 129 // Obviously, this is suboptimal and should be addressed once ubercompositor | |
| 130 // starts shaping up. | |
|
piman
2013/04/08 21:03:47
(not for this CL) would it make sense to move the
danakj
2013/04/08 21:44:56
I think we should only be generating 1 mailbox vid
| |
| 131 if (software_compositor) { | |
| 132 output_resource_format = kRGBResourceFormat; | |
| 133 output_plane_count = 1; | |
| 134 } | |
| 135 | |
| 136 int max_resource_size = resource_provider_->max_texture_size(); | |
| 137 gfx::Size coded_frame_size = video_frame->coded_size(); | |
| 138 | |
| 139 ResourceProvider::ResourceIdArray plane_resources; | |
| 140 bool allocation_success = true; | |
| 141 | |
| 142 for (size_t i = 0; i < output_plane_count; ++i) { | |
| 143 gfx::Size plane_size = | |
| 144 SoftwarePlaneDimension(input_frame_format, | |
| 145 coded_frame_size, | |
| 146 output_resource_format, | |
| 147 i); | |
| 148 if (plane_size.IsEmpty() || | |
| 149 plane_size.width() > max_resource_size || | |
| 150 plane_size.height() > max_resource_size) { | |
| 151 allocation_success = false; | |
| 152 break; | |
| 153 } | |
| 154 | |
| 155 // TODO(danakj): Could recycle resources that we previously allocated and | |
| 156 // were returned to us. | |
|
piman
2013/04/08 21:03:47
I think this is important. genMailboxCHROMIUM is a
danakj
2013/04/08 21:44:56
OK, I will do this in my next CL, is that sufficie
| |
| 157 ResourceProvider::ResourceId resource_id = | |
| 158 resource_provider_->CreateResource(plane_size, | |
| 159 output_resource_format, | |
| 160 ResourceProvider::TextureUsageAny); | |
| 161 if (resource_id == 0) { | |
| 162 allocation_success = false; | |
| 163 break; | |
| 164 } | |
| 165 | |
| 166 plane_resources.push_back(resource_id); | |
| 167 } | |
| 168 | |
| 169 if (!allocation_success) { | |
| 170 for (size_t i = 0; i < plane_resources.size(); ++i) | |
| 171 resource_provider_->DeleteResource(plane_resources[i]); | |
| 172 return VideoFrameExternalResources(); | |
| 173 } | |
| 174 | |
| 175 VideoFrameExternalResources external_resources; | |
| 176 | |
| 177 if (software_compositor) { | |
| 178 DCHECK_EQ(output_resource_format, kRGBResourceFormat); | |
| 179 DCHECK_EQ(plane_resources.size(), 1u); | |
| 180 | |
| 181 if (!video_renderer_) | |
| 182 video_renderer_.reset(new media::SkCanvasVideoRenderer); | |
| 183 | |
| 184 { | |
| 185 ResourceProvider::ScopedWriteLockSoftware lock( | |
| 186 resource_provider_, plane_resources[0]); | |
| 187 video_renderer_->Paint(video_frame, | |
| 188 lock.sk_canvas(), | |
| 189 video_frame->visible_rect(), | |
| 190 0xff); | |
| 191 } | |
| 192 | |
| 193 TextureMailbox::ReleaseCallback callback_to_free_resource = | |
| 194 base::Bind(&ReleaseResource, | |
| 195 resource_provider_->AsWeakPtr(), | |
| 196 plane_resources[0]); | |
| 197 external_resources.software_resources.push_back(plane_resources[0]); | |
| 198 external_resources.software_release_callback = callback_to_free_resource; | |
| 199 | |
| 200 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; | |
| 201 return external_resources; | |
| 202 } | |
| 203 | |
| 204 DCHECK_EQ(output_resource_format, | |
| 205 static_cast<unsigned>(kYUVResourceFormat)); | |
| 206 | |
| 207 WebKit::WebGraphicsContext3D* context = | |
| 208 resource_provider_->GraphicsContext3D(); | |
| 209 DCHECK(context); | |
| 210 | |
| 211 for (size_t plane = 0; plane < plane_resources.size(); ++plane) { | |
| 212 // Update each plane's resource id with its content. | |
| 213 ResourceProvider::ResourceId output_plane_resource_id = | |
| 214 plane_resources[plane]; | |
| 215 gfx::Size plane_size = | |
| 216 SoftwarePlaneDimension(input_frame_format, | |
| 217 coded_frame_size, | |
| 218 output_resource_format, | |
| 219 plane); | |
| 220 const uint8_t* input_plane_pixels = video_frame->data(plane); | |
| 221 | |
| 222 gfx::Rect image_rect( | |
| 223 0, 0, video_frame->stride(plane), plane_size.height()); | |
| 224 gfx::Rect source_rect(plane_size); | |
| 225 resource_provider_->SetPixels(output_plane_resource_id, | |
| 226 input_plane_pixels, | |
| 227 image_rect, | |
| 228 source_rect, | |
| 229 gfx::Vector2d()); | |
| 230 | |
| 231 gpu::Mailbox mailbox; | |
| 232 { | |
| 233 ResourceProvider::ScopedWriteLockGL lock( | |
| 234 resource_provider_, output_plane_resource_id); | |
| 235 | |
| 236 GLC(context, context->genMailboxCHROMIUM(mailbox.name)); | |
| 237 GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id())); | |
| 238 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, | |
| 239 mailbox.name)); | |
| 240 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); | |
| 241 } | |
| 242 | |
| 243 TextureMailbox::ReleaseCallback callback_to_free_resource = | |
| 244 base::Bind(&ReleaseResource, | |
| 245 resource_provider_->AsWeakPtr(), | |
| 246 output_plane_resource_id); | |
| 247 external_resources.mailboxes.push_back( | |
| 248 TextureMailbox(mailbox, callback_to_free_resource)); | |
| 249 } | |
| 250 | |
| 251 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; | |
| 252 return external_resources; | |
| 253 } | |
| 254 | |
| 255 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( | |
| 256 const scoped_refptr<media::VideoFrame>& video_frame, | |
| 257 const TextureMailbox::ReleaseCallback& release_callback) { | |
| 258 if (!VerifyFrame(video_frame)) | |
| 259 return VideoFrameExternalResources(); | |
| 260 | |
| 261 media::VideoFrame::Format frame_format = video_frame->format(); | |
| 262 | |
| 263 DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE); | |
| 264 if (frame_format != media::VideoFrame::NATIVE_TEXTURE) | |
| 265 return VideoFrameExternalResources(); | |
| 266 | |
| 267 WebKit::WebGraphicsContext3D* context = | |
| 268 resource_provider_->GraphicsContext3D(); | |
| 269 if (!context) | |
| 270 return VideoFrameExternalResources(); | |
| 271 | |
| 272 VideoFrameExternalResources external_resources; | |
| 273 switch (video_frame->texture_target()) { | |
| 274 case GL_TEXTURE_2D: | |
| 275 external_resources.type = VideoFrameExternalResources::RGB_RESOURCE; | |
| 276 break; | |
| 277 case GL_TEXTURE_EXTERNAL_OES: | |
| 278 external_resources.type = | |
| 279 VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE; | |
| 280 break; | |
| 281 case GL_TEXTURE_RECTANGLE_ARB: | |
| 282 external_resources.type = VideoFrameExternalResources::IO_SURFACE; | |
| 283 break; | |
| 284 default: | |
| 285 NOTREACHED(); | |
| 286 return VideoFrameExternalResources(); | |
| 287 } | |
| 288 | |
| 289 gpu::Mailbox mailbox; | |
| 290 GLC(context, context->genMailboxCHROMIUM(mailbox.name)); | |
| 291 GLC(context, context->bindTexture(GL_TEXTURE_2D, video_frame->texture_id())); | |
| 292 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); | |
| 293 GLC(context, context->bindTexture(GL_TEXTURE_2D, 0)); | |
| 294 | |
| 295 external_resources.mailboxes.push_back( | |
| 296 TextureMailbox(mailbox, release_callback)); | |
| 297 return external_resources; | |
| 298 } | |
| 299 | |
| 300 } // namespace cc | |
| OLD | NEW |