Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(489)

Side by Side Diff: cc/resources/video_resource_updater.cc

Issue 812543002: Update from https://crrev.com/308331 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/resources/video_resource_updater_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/resources/video_resource_updater.h" 5 #include "cc/resources/video_resource_updater.h"
6 6
7 #include <algorithm>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
9 #include "cc/output/gl_renderer.h" 11 #include "cc/output/gl_renderer.h"
10 #include "cc/resources/resource_provider.h" 12 #include "cc/resources/resource_provider.h"
11 #include "gpu/GLES2/gl2extchromium.h" 13 #include "gpu/GLES2/gl2extchromium.h"
12 #include "gpu/command_buffer/client/gles2_interface.h" 14 #include "gpu/command_buffer/client/gles2_interface.h"
13 #include "media/base/video_frame.h" 15 #include "media/base/video_frame.h"
14 #include "media/filters/skcanvas_video_renderer.h" 16 #include "media/filters/skcanvas_video_renderer.h"
15 #include "third_party/khronos/GLES2/gl2.h" 17 #include "third_party/khronos/GLES2/gl2.h"
16 #include "third_party/khronos/GLES2/gl2ext.h" 18 #include "third_party/khronos/GLES2/gl2ext.h"
(...skipping 24 matching lines...) Expand all
41 43
42 VideoResourceUpdater::PlaneResource::PlaneResource( 44 VideoResourceUpdater::PlaneResource::PlaneResource(
43 unsigned int resource_id, 45 unsigned int resource_id,
44 const gfx::Size& resource_size, 46 const gfx::Size& resource_size,
45 ResourceFormat resource_format, 47 ResourceFormat resource_format,
46 gpu::Mailbox mailbox) 48 gpu::Mailbox mailbox)
47 : resource_id(resource_id), 49 : resource_id(resource_id),
48 resource_size(resource_size), 50 resource_size(resource_size),
49 resource_format(resource_format), 51 resource_format(resource_format),
50 mailbox(mailbox), 52 mailbox(mailbox),
53 ref_count(0),
51 frame_ptr(nullptr), 54 frame_ptr(nullptr),
52 plane_index(0) { 55 plane_index(0) {
53 } 56 }
54 57
55 bool VideoResourceUpdater::PlaneResourceMatchesUniqueID( 58 bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
56 const PlaneResource& plane_resource, 59 const PlaneResource& plane_resource,
57 const media::VideoFrame* video_frame, 60 const media::VideoFrame* video_frame,
58 int plane_index) { 61 int plane_index) {
59 return plane_resource.frame_ptr == video_frame && 62 return plane_resource.frame_ptr == video_frame &&
60 plane_resource.plane_index == plane_index && 63 plane_resource.plane_index == plane_index &&
(...skipping 13 matching lines...) Expand all
74 77
75 VideoFrameExternalResources::~VideoFrameExternalResources() {} 78 VideoFrameExternalResources::~VideoFrameExternalResources() {}
76 79
77 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider, 80 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
78 ResourceProvider* resource_provider) 81 ResourceProvider* resource_provider)
79 : context_provider_(context_provider), 82 : context_provider_(context_provider),
80 resource_provider_(resource_provider) { 83 resource_provider_(resource_provider) {
81 } 84 }
82 85
83 VideoResourceUpdater::~VideoResourceUpdater() { 86 VideoResourceUpdater::~VideoResourceUpdater() {
84 while (!all_resources_.empty()) { 87 for (const PlaneResource& plane_resource : all_resources_)
85 resource_provider_->DeleteResource(all_resources_.back()); 88 resource_provider_->DeleteResource(plane_resource.resource_id);
86 all_resources_.pop_back();
87 }
88 } 89 }
89 90
90 void VideoResourceUpdater::DeleteResource(unsigned resource_id) { 91 VideoResourceUpdater::ResourceList::iterator
91 resource_provider_->DeleteResource(resource_id); 92 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
92 all_resources_.erase(std::remove(all_resources_.begin(), 93 ResourceFormat format,
93 all_resources_.end(), 94 bool has_mailbox) {
94 resource_id)); 95 // TODO(danakj): Abstract out hw/sw resource create/delete from
96 // ResourceProvider and stop using ResourceProvider in this class.
97 const ResourceProvider::ResourceId resource_id =
98 resource_provider_->CreateResource(plane_size, GL_CLAMP_TO_EDGE,
99 ResourceProvider::TextureHintImmutable,
100 format);
101 if (resource_id == 0)
102 return all_resources_.end();
103
104 gpu::Mailbox mailbox;
105 if (has_mailbox) {
106 DCHECK(context_provider_);
107
108 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
109
110 GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
111 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
112 GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
113 mailbox.name));
114 }
115 all_resources_.push_front(
116 PlaneResource(resource_id, plane_size, format, mailbox));
117 return all_resources_.begin();
118 }
119
120 void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) {
121 DCHECK_EQ(resource_it->ref_count, 0);
122 resource_provider_->DeleteResource(resource_it->resource_id);
123 all_resources_.erase(resource_it);
95 } 124 }
96 125
97 VideoFrameExternalResources VideoResourceUpdater:: 126 VideoFrameExternalResources VideoResourceUpdater::
98 CreateExternalResourcesFromVideoFrame( 127 CreateExternalResourcesFromVideoFrame(
99 const scoped_refptr<media::VideoFrame>& video_frame) { 128 const scoped_refptr<media::VideoFrame>& video_frame) {
100 if (!VerifyFrame(video_frame)) 129 if (!VerifyFrame(video_frame))
101 return VideoFrameExternalResources(); 130 return VideoFrameExternalResources();
102 131
103 if (video_frame->format() == media::VideoFrame::NATIVE_TEXTURE) 132 if (video_frame->format() == media::VideoFrame::NATIVE_TEXTURE)
104 return CreateForHardwarePlanes(video_frame); 133 return CreateForHardwarePlanes(video_frame);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 179
151 #if defined(VIDEO_HOLE) 180 #if defined(VIDEO_HOLE)
152 if (input_frame_format == media::VideoFrame::HOLE) { 181 if (input_frame_format == media::VideoFrame::HOLE) {
153 VideoFrameExternalResources external_resources; 182 VideoFrameExternalResources external_resources;
154 external_resources.type = VideoFrameExternalResources::HOLE; 183 external_resources.type = VideoFrameExternalResources::HOLE;
155 return external_resources; 184 return external_resources;
156 } 185 }
157 #endif // defined(VIDEO_HOLE) 186 #endif // defined(VIDEO_HOLE)
158 187
159 // Only YUV software video frames are supported. 188 // Only YUV software video frames are supported.
160 DCHECK(input_frame_format == media::VideoFrame::YV12 ||
161 input_frame_format == media::VideoFrame::I420 ||
162 input_frame_format == media::VideoFrame::YV12A ||
163 input_frame_format == media::VideoFrame::YV12J ||
164 input_frame_format == media::VideoFrame::YV16 ||
165 input_frame_format == media::VideoFrame::YV24);
166 if (input_frame_format != media::VideoFrame::YV12 && 189 if (input_frame_format != media::VideoFrame::YV12 &&
167 input_frame_format != media::VideoFrame::I420 && 190 input_frame_format != media::VideoFrame::I420 &&
168 input_frame_format != media::VideoFrame::YV12A && 191 input_frame_format != media::VideoFrame::YV12A &&
169 input_frame_format != media::VideoFrame::YV12J && 192 input_frame_format != media::VideoFrame::YV12J &&
170 input_frame_format != media::VideoFrame::YV16 && 193 input_frame_format != media::VideoFrame::YV16 &&
171 input_frame_format != media::VideoFrame::YV24) 194 input_frame_format != media::VideoFrame::YV24) {
195 NOTREACHED() << input_frame_format;
172 return VideoFrameExternalResources(); 196 return VideoFrameExternalResources();
197 }
173 198
174 bool software_compositor = context_provider_ == NULL; 199 bool software_compositor = context_provider_ == NULL;
175 200
176 ResourceFormat output_resource_format = 201 ResourceFormat output_resource_format =
177 resource_provider_->yuv_resource_format(); 202 resource_provider_->yuv_resource_format();
178 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); 203 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
179 204
180 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB 205 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
181 // conversion here. That involves an extra copy of each frame to a bitmap. 206 // conversion here. That involves an extra copy of each frame to a bitmap.
182 // Obviously, this is suboptimal and should be addressed once ubercompositor 207 // Obviously, this is suboptimal and should be addressed once ubercompositor
183 // starts shaping up. 208 // starts shaping up.
184 if (software_compositor) { 209 if (software_compositor) {
185 output_resource_format = kRGBResourceFormat; 210 output_resource_format = kRGBResourceFormat;
186 output_plane_count = 1; 211 output_plane_count = 1;
187 } 212 }
188 213
189 int max_resource_size = resource_provider_->max_texture_size(); 214 // Drop recycled resources that are the wrong format.
190 std::vector<PlaneResource> plane_resources; 215 for (auto it = all_resources_.begin(); it != all_resources_.end();) {
191 bool allocation_success = true; 216 if (it->ref_count == 0 && it->resource_format != output_resource_format)
217 DeleteResource(it++);
218 else
219 ++it;
220 }
192 221
222 const int max_resource_size = resource_provider_->max_texture_size();
223 std::vector<ResourceList::iterator> plane_resources;
193 for (size_t i = 0; i < output_plane_count; ++i) { 224 for (size_t i = 0; i < output_plane_count; ++i) {
194 gfx::Size output_plane_resource_size = 225 gfx::Size output_plane_resource_size =
195 SoftwarePlaneDimension(video_frame, software_compositor, i); 226 SoftwarePlaneDimension(video_frame, software_compositor, i);
196 if (output_plane_resource_size.IsEmpty() || 227 if (output_plane_resource_size.IsEmpty() ||
197 output_plane_resource_size.width() > max_resource_size || 228 output_plane_resource_size.width() > max_resource_size ||
198 output_plane_resource_size.height() > max_resource_size) { 229 output_plane_resource_size.height() > max_resource_size) {
199 allocation_success = false;
200 break; 230 break;
201 } 231 }
202 232
203 // Try recycle a previously-allocated resource. 233 // Try recycle a previously-allocated resource.
204 auto recycled_it = recycled_resources_.end(); 234 ResourceList::iterator resource_it = all_resources_.end();
205 for (auto it = recycled_resources_.begin(); it != recycled_resources_.end(); 235 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
206 ++it) { 236 if (it->resource_size == output_plane_resource_size &&
207 const bool resource_matches = 237 it->resource_format == output_resource_format) {
208 it->resource_format == output_resource_format && 238 if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) {
209 it->resource_size == output_plane_resource_size; 239 // Bingo, we found a resource that already contains the data we are
210 const bool in_use = software_compositor && 240 // planning to put in it. It's safe to reuse it even if
211 resource_provider_->InUseByConsumer(it->resource_id); 241 // resource_provider_ holds some references to it, because those
212 if (resource_matches && !in_use) { 242 // references are read-only.
213 // We found a recycled resource with the allocation size and format we 243 resource_it = it;
214 // are looking for.
215 recycled_it = it;
216 // Keep looking for a recycled resource that also contains the data we
217 // are planning to put in it.
218 if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i))
219 break; 244 break;
245 }
246
247 // This extra check is needed because resources backed by SharedMemory
248 // are not ref-counted, unlike mailboxes. Full discussion in
249 // codereview.chromium.org/145273021.
250 const bool in_use =
251 software_compositor &&
252 resource_provider_->InUseByConsumer(it->resource_id);
253 if (it->ref_count == 0 && !in_use) {
254 // We found a resource with the correct size that we can overwrite.
255 resource_it = it;
256 }
220 } 257 }
221 } 258 }
222 259
223 // Check if we can avoid allocating a new resource. 260 // Check if we need to allocate a new resource.
224 if (recycled_it != recycled_resources_.end()) { 261 if (resource_it == all_resources_.end()) {
225 plane_resources.push_back(*recycled_it); 262 resource_it =
226 recycled_resources_.erase(recycled_it); 263 AllocateResource(output_plane_resource_size, output_resource_format,
227 continue; 264 !software_compositor);
228 } 265 }
266 if (resource_it == all_resources_.end())
267 break;
229 268
230 // TODO(danakj): Abstract out hw/sw resource create/delete from 269 ++resource_it->ref_count;
231 // ResourceProvider and stop using ResourceProvider in this class. 270 plane_resources.push_back(resource_it);
232 const ResourceProvider::ResourceId resource_id =
233 resource_provider_->CreateResource(
234 output_plane_resource_size, GL_CLAMP_TO_EDGE,
235 ResourceProvider::TextureHintImmutable, output_resource_format);
236 if (resource_id == 0) {
237 allocation_success = false;
238 break;
239 }
240 all_resources_.push_back(resource_id);
241
242 gpu::Mailbox mailbox;
243 if (!software_compositor) {
244 DCHECK(context_provider_);
245
246 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
247
248 GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
249 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
250 GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
251 mailbox.name));
252 }
253
254 DCHECK(software_compositor || !mailbox.IsZero());
255 plane_resources.push_back(PlaneResource(resource_id,
256 output_plane_resource_size,
257 output_resource_format,
258 mailbox));
259 } 271 }
260 272
261 if (!allocation_success) { 273 if (plane_resources.size() != output_plane_count) {
262 for (size_t i = 0; i < plane_resources.size(); ++i) 274 // Allocation failed, nothing will be returned so restore reference counts.
263 DeleteResource(plane_resources[i].resource_id); 275 for (ResourceList::iterator resource_it : plane_resources)
276 --resource_it->ref_count;
264 return VideoFrameExternalResources(); 277 return VideoFrameExternalResources();
265 } 278 }
266 279
267 VideoFrameExternalResources external_resources; 280 VideoFrameExternalResources external_resources;
268 281
269 if (software_compositor) { 282 if (software_compositor) {
270 DCHECK_EQ(plane_resources.size(), 1u); 283 DCHECK_EQ(plane_resources.size(), 1u);
271 DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat); 284 PlaneResource& plane_resource = *plane_resources[0];
272 DCHECK(plane_resources[0].mailbox.IsZero()); 285 DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat);
286 DCHECK(plane_resource.mailbox.IsZero());
273 287
274 if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(), 288 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), 0)) {
275 0)) {
276 // We need to transfer data from |video_frame| to the plane resource. 289 // We need to transfer data from |video_frame| to the plane resource.
277 if (!video_renderer_) 290 if (!video_renderer_)
278 video_renderer_.reset(new media::SkCanvasVideoRenderer); 291 video_renderer_.reset(new media::SkCanvasVideoRenderer);
279 292
280 ResourceProvider::ScopedWriteLockSoftware lock( 293 ResourceProvider::ScopedWriteLockSoftware lock(
281 resource_provider_, plane_resources[0].resource_id); 294 resource_provider_, plane_resource.resource_id);
282 SkCanvas canvas(lock.sk_bitmap()); 295 SkCanvas canvas(lock.sk_bitmap());
283 video_renderer_->Copy(video_frame, &canvas); 296 video_renderer_->Copy(video_frame, &canvas);
284 SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]); 297 SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
285 } 298 }
286 299
287 external_resources.software_resources.push_back( 300 external_resources.software_resources.push_back(plane_resource.resource_id);
288 plane_resources[0].resource_id);
289 external_resources.software_release_callback = 301 external_resources.software_release_callback =
290 base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]); 302 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id);
291 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; 303 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
292
293 return external_resources; 304 return external_resources;
294 } 305 }
295 306
296 for (size_t i = 0; i < plane_resources.size(); ++i) { 307 for (size_t i = 0; i < plane_resources.size(); ++i) {
308 PlaneResource& plane_resource = *plane_resources[i];
297 // Update each plane's resource id with its content. 309 // Update each plane's resource id with its content.
298 DCHECK_EQ(plane_resources[i].resource_format, 310 DCHECK_EQ(plane_resource.resource_format,
299 resource_provider_->yuv_resource_format()); 311 resource_provider_->yuv_resource_format());
300 312
301 if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(), 313 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
302 i)) {
303 // We need to transfer data from |video_frame| to the plane resource. 314 // We need to transfer data from |video_frame| to the plane resource.
304 const uint8_t* input_plane_pixels = video_frame->data(i); 315 const uint8_t* input_plane_pixels = video_frame->data(i);
305 316
306 gfx::Rect image_rect(0, 0, video_frame->stride(i), 317 gfx::Rect image_rect(0, 0, video_frame->stride(i),
307 plane_resources[i].resource_size.height()); 318 plane_resource.resource_size.height());
308 gfx::Rect source_rect(plane_resources[i].resource_size); 319 gfx::Rect source_rect(plane_resource.resource_size);
309 resource_provider_->SetPixels(plane_resources[i].resource_id, 320 resource_provider_->SetPixels(plane_resource.resource_id,
310 input_plane_pixels, image_rect, source_rect, 321 input_plane_pixels, image_rect, source_rect,
311 gfx::Vector2d()); 322 gfx::Vector2d());
312 SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]); 323 SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
313 } 324 }
314 325
315 external_resources.mailboxes.push_back( 326 external_resources.mailboxes.push_back(
316 TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0)); 327 TextureMailbox(plane_resource.mailbox, GL_TEXTURE_2D, 0));
317 external_resources.release_callbacks.push_back( 328 external_resources.release_callbacks.push_back(
318 base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i])); 329 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id));
319 } 330 }
320 331
321 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; 332 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
322 return external_resources; 333 return external_resources;
323 } 334 }
324 335
325 // static 336 // static
326 void VideoResourceUpdater::ReturnTexture( 337 void VideoResourceUpdater::ReturnTexture(
327 base::WeakPtr<VideoResourceUpdater> updater, 338 base::WeakPtr<VideoResourceUpdater> updater,
328 const scoped_refptr<media::VideoFrame>& video_frame, 339 const scoped_refptr<media::VideoFrame>& video_frame,
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 mailbox_holder->texture_target, 386 mailbox_holder->texture_target,
376 mailbox_holder->sync_point)); 387 mailbox_holder->sync_point));
377 external_resources.release_callbacks.push_back( 388 external_resources.release_callbacks.push_back(
378 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); 389 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
379 return external_resources; 390 return external_resources;
380 } 391 }
381 392
382 // static 393 // static
383 void VideoResourceUpdater::RecycleResource( 394 void VideoResourceUpdater::RecycleResource(
384 base::WeakPtr<VideoResourceUpdater> updater, 395 base::WeakPtr<VideoResourceUpdater> updater,
385 PlaneResource data, 396 ResourceProvider::ResourceId resource_id,
386 uint32 sync_point, 397 uint32 sync_point,
387 bool lost_resource, 398 bool lost_resource,
388 BlockingTaskRunner* main_thread_task_runner) { 399 BlockingTaskRunner* main_thread_task_runner) {
389 if (!updater.get()) { 400 if (!updater.get()) {
390 // Resource was already deleted. 401 // Resource was already deleted.
391 return; 402 return;
392 } 403 }
393 404
405 const ResourceList::iterator resource_it = std::find_if(
406 updater->all_resources_.begin(), updater->all_resources_.end(),
407 [resource_id](const PlaneResource& plane_resource) {
408 return plane_resource.resource_id == resource_id;
409 });
410 if (resource_it == updater->all_resources_.end())
411 return;
412
394 ContextProvider* context_provider = updater->context_provider_; 413 ContextProvider* context_provider = updater->context_provider_;
395 if (context_provider && sync_point) { 414 if (context_provider && sync_point) {
396 GLC(context_provider->ContextGL(), 415 GLC(context_provider->ContextGL(),
397 context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point)); 416 context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point));
398 } 417 }
399 418
400 if (lost_resource) { 419 if (lost_resource) {
401 updater->DeleteResource(data.resource_id); 420 resource_it->ref_count = 0;
421 updater->DeleteResource(resource_it);
402 return; 422 return;
403 } 423 }
404 424
405 // Drop recycled resources that are the wrong format. 425 --resource_it->ref_count;
406 while (!updater->recycled_resources_.empty() && 426 DCHECK_GE(resource_it->ref_count, 0);
407 updater->recycled_resources_.back().resource_format !=
408 data.resource_format) {
409 updater->DeleteResource(updater->recycled_resources_.back().resource_id);
410 updater->recycled_resources_.pop_back();
411 }
412
413 updater->recycled_resources_.push_back(data);
414 } 427 }
415 428
416 } // namespace cc 429 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/resources/video_resource_updater_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698