OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "media/filters/skcanvas_video_renderer.h" | 5 #include "media/filters/skcanvas_video_renderer.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "gpu/GLES2/gl2extchromium.h" | |
9 #include "gpu/command_buffer/client/gles2_interface.h" | |
10 #include "gpu/command_buffer/common/mailbox_holder.h" | |
8 #include "media/base/video_frame.h" | 11 #include "media/base/video_frame.h" |
9 #include "media/base/yuv_convert.h" | 12 #include "media/base/yuv_convert.h" |
13 #include "skia/ext/refptr.h" | |
10 #include "third_party/libyuv/include/libyuv.h" | 14 #include "third_party/libyuv/include/libyuv.h" |
11 #include "third_party/skia/include/core/SkCanvas.h" | 15 #include "third_party/skia/include/core/SkCanvas.h" |
12 #include "third_party/skia/include/core/SkImageGenerator.h" | 16 #include "third_party/skia/include/core/SkImageGenerator.h" |
17 #include "third_party/skia/include/gpu/GrContext.h" | |
18 #include "third_party/skia/include/gpu/SkGrPixelRef.h" | |
13 #include "ui/gfx/skbitmap_operations.h" | 19 #include "ui/gfx/skbitmap_operations.h" |
14 | 20 |
15 // Skia internal format depends on a platform. On Android it is ABGR, on others | 21 // Skia internal format depends on a platform. On Android it is ABGR, on others |
16 // it is ARGB. | 22 // it is ARGB. |
17 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ | 23 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ |
18 SK_A32_SHIFT == 24 | 24 SK_A32_SHIFT == 24 |
19 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB | 25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB |
20 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB | 26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB |
21 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ | 27 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ |
22 SK_A32_SHIFT == 24 | 28 SK_A32_SHIFT == 24 |
23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR | 29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR |
24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR | 30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR |
25 #else | 31 #else |
26 #error Unexpected Skia ARGB_8888 layout! | 32 #error Unexpected Skia ARGB_8888 layout! |
27 #endif | 33 #endif |
28 | 34 |
29 namespace media { | 35 namespace media { |
30 | 36 |
31 static bool IsYUV(media::VideoFrame::Format format) { | 37 namespace { |
38 | |
39 // This class keeps two temporary resources; software bitmap, hardware bitmap. | |
40 // If both bitmap are created and then only software bitmap is updated every | |
41 // frame, hardware bitmap outlives until the media player dies. So we delete | |
42 // a temporary resource if it is not used for 3 sec. | |
43 const int kTemporaryResourceDeletionDelay = 3; // Seconds; | |
scherkus (not reviewing)
2014/10/15 17:10:23
note this is in media time, which has little relat
| |
44 | |
45 bool IsYUV(media::VideoFrame::Format format) { | |
32 switch (format) { | 46 switch (format) { |
33 case VideoFrame::YV12: | 47 case VideoFrame::YV12: |
34 case VideoFrame::YV16: | 48 case VideoFrame::YV16: |
35 case VideoFrame::I420: | 49 case VideoFrame::I420: |
36 case VideoFrame::YV12A: | 50 case VideoFrame::YV12A: |
37 case VideoFrame::YV12J: | 51 case VideoFrame::YV12J: |
38 case VideoFrame::YV24: | 52 case VideoFrame::YV24: |
39 case VideoFrame::NV12: | 53 case VideoFrame::NV12: |
40 return true; | 54 return true; |
41 case VideoFrame::UNKNOWN: | 55 case VideoFrame::UNKNOWN: |
42 case VideoFrame::NATIVE_TEXTURE: | 56 case VideoFrame::NATIVE_TEXTURE: |
43 #if defined(VIDEO_HOLE) | 57 #if defined(VIDEO_HOLE) |
44 case VideoFrame::HOLE: | 58 case VideoFrame::HOLE: |
45 #endif // defined(VIDEO_HOLE) | 59 #endif // defined(VIDEO_HOLE) |
46 return false; | 60 return false; |
47 } | 61 } |
48 NOTREACHED() << "Invalid videoframe format provided: " << format; | 62 NOTREACHED() << "Invalid videoframe format provided: " << format; |
49 return false; | 63 return false; |
50 } | 64 } |
51 | 65 |
52 static bool IsJPEGColorSpace(media::VideoFrame::Format format) { | 66 bool IsJPEGColorSpace(media::VideoFrame::Format format) { |
53 switch (format) { | 67 switch (format) { |
54 case VideoFrame::YV12J: | 68 case VideoFrame::YV12J: |
55 return true; | 69 return true; |
56 case VideoFrame::YV12: | 70 case VideoFrame::YV12: |
57 case VideoFrame::YV16: | 71 case VideoFrame::YV16: |
58 case VideoFrame::I420: | 72 case VideoFrame::I420: |
59 case VideoFrame::YV12A: | 73 case VideoFrame::YV12A: |
60 case VideoFrame::YV24: | 74 case VideoFrame::YV24: |
61 case VideoFrame::NV12: | 75 case VideoFrame::NV12: |
62 case VideoFrame::UNKNOWN: | 76 case VideoFrame::UNKNOWN: |
63 case VideoFrame::NATIVE_TEXTURE: | 77 case VideoFrame::NATIVE_TEXTURE: |
64 #if defined(VIDEO_HOLE) | 78 #if defined(VIDEO_HOLE) |
65 case VideoFrame::HOLE: | 79 case VideoFrame::HOLE: |
66 #endif // defined(VIDEO_HOLE) | 80 #endif // defined(VIDEO_HOLE) |
67 return false; | 81 return false; |
68 } | 82 } |
69 NOTREACHED() << "Invalid videoframe format provided: " << format; | 83 NOTREACHED() << "Invalid videoframe format provided: " << format; |
70 return false; | 84 return false; |
71 } | 85 } |
72 | 86 |
73 static bool IsYUVOrNative(media::VideoFrame::Format format) { | 87 bool IsYUVOrNative(media::VideoFrame::Format format) { |
74 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; | 88 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
75 } | 89 } |
76 | 90 |
77 // Converts a |video_frame| to raw |rgb_pixels|. | 91 // Converts a |video_frame| to raw |rgb_pixels|. |
78 static void ConvertVideoFrameToRGBPixels( | 92 void ConvertVideoFrameToRGBPixels( |
79 const scoped_refptr<media::VideoFrame>& video_frame, | 93 const scoped_refptr<media::VideoFrame>& video_frame, |
80 void* rgb_pixels, | 94 void* rgb_pixels, |
81 size_t row_bytes) { | 95 size_t row_bytes) { |
82 DCHECK(IsYUVOrNative(video_frame->format())) | 96 DCHECK(IsYUVOrNative(video_frame->format())) |
83 << video_frame->format(); | 97 << video_frame->format(); |
84 if (IsYUV(video_frame->format())) { | 98 if (IsYUV(video_frame->format())) { |
85 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 99 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
86 video_frame->stride(media::VideoFrame::kVPlane)); | 100 video_frame->stride(media::VideoFrame::kVPlane)); |
87 } | 101 } |
88 | 102 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 row_bytes); | 212 row_bytes); |
199 video_frame->ReadPixelsFromNativeTexture(tmp); | 213 video_frame->ReadPixelsFromNativeTexture(tmp); |
200 break; | 214 break; |
201 } | 215 } |
202 default: | 216 default: |
203 NOTREACHED(); | 217 NOTREACHED(); |
204 break; | 218 break; |
205 } | 219 } |
206 } | 220 } |
207 | 221 |
222 bool EnsureTextureBackedSkBitmap(GrContext* gr, | |
scherkus (not reviewing)
2014/10/15 17:10:23
I know you lifted this code from WebMediaPlayerAnd
| |
223 SkBitmap* bitmap, | |
224 const gfx::Size& size) { | |
225 if (!bitmap->getTexture() || bitmap->width() != size.width() || | |
226 bitmap->height() != size.height()) { | |
227 if (!gr) | |
228 return false; | |
229 GrTextureDesc desc; | |
230 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, because | |
231 // glCopyTextureChromium doesn't support GL_BGRA_EXT as internal format. | |
232 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
233 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
234 desc.fSampleCnt = 0; | |
235 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
236 desc.fWidth = size.width(); | |
237 desc.fHeight = size.height(); | |
238 GrAutoScratchTexture scratch_texture( | |
239 gr, desc, GrContext::kExact_ScratchTexMatch); | |
240 skia::RefPtr<GrTexture> texture = skia::AdoptRef(scratch_texture.detach()); | |
241 if (!texture.get()) | |
242 return false; | |
243 | |
244 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight); | |
245 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, texture.get())); | |
246 if (!pixelRef) | |
247 return false; | |
248 bitmap->setInfo(info); | |
249 bitmap->setPixelRef(pixelRef)->unref(); | |
250 } | |
251 | |
252 return true; | |
253 } | |
254 | |
255 bool ConvertVideoFrameToTexture( | |
scherkus (not reviewing)
2014/10/15 17:10:23
considering all the various combinations of sw vs.
| |
256 VideoFrame* video_frame, | |
257 SkBitmap* bitmap, | |
258 SkCanvasVideoRenderer::Context3DProvider* context_provider) { | |
259 DCHECK(context_provider && context_provider->gl && | |
260 context_provider->gr_context && | |
261 video_frame->format() == VideoFrame::NATIVE_TEXTURE); | |
262 | |
263 // Check if we could reuse existing texture based bitmap. | |
264 // Otherwise, release existing texture based bitmap and allocate | |
265 // a new one based on video size. | |
266 if (!EnsureTextureBackedSkBitmap(context_provider->gr_context, | |
267 bitmap, | |
268 video_frame->visible_rect().size())) { | |
269 return false; | |
270 } | |
271 | |
272 unsigned textureId = | |
scherkus (not reviewing)
2014/10/15 17:10:24
textureId -> texture_id
| |
273 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); | |
274 // If CopyVideoFrameToTexture() changes the state of the 'textureId', it's | |
275 // needed to invalidate the state cached in skia, but currently the state | |
276 // isn't changed. | |
277 SkCanvasVideoRenderer::CopyVideoFrameToTexture(context_provider->gl, | |
278 video_frame, | |
279 textureId, | |
280 0, | |
281 GL_RGBA, | |
282 GL_UNSIGNED_BYTE, | |
283 true, | |
284 false); | |
285 return true; | |
286 } | |
287 | |
288 class SyncPointClientImpl : public VideoFrame::SyncPointClient { | |
289 public: | |
290 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} | |
291 virtual ~SyncPointClientImpl() {} | |
292 virtual uint32 InsertSyncPoint() OVERRIDE { | |
293 return gl_->InsertSyncPointCHROMIUM(); | |
294 } | |
295 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE { | |
296 gl_->WaitSyncPointCHROMIUM(sync_point); | |
297 } | |
298 | |
299 private: | |
300 gpu::gles2::GLES2Interface* gl_; | |
301 }; | |
302 | |
303 bool IsNull(SkCanvasVideoRenderer::Context3DProvider* context_provider) { | |
304 return !context_provider || | |
305 !(context_provider->gl && context_provider->gr_context); | |
306 } | |
307 | |
308 } // anonymous namespace | |
309 | |
208 // Generates an RGB image from a VideoFrame. | 310 // Generates an RGB image from a VideoFrame. |
209 class VideoImageGenerator : public SkImageGenerator { | 311 class VideoImageGenerator : public SkImageGenerator { |
210 public: | 312 public: |
211 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) { | 313 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) { |
212 DCHECK(frame_.get()); | 314 DCHECK(frame_.get()); |
213 } | 315 } |
214 virtual ~VideoImageGenerator() {} | 316 virtual ~VideoImageGenerator() {} |
215 | 317 |
216 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } | 318 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } |
217 | 319 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
282 return true; | 384 return true; |
283 } | 385 } |
284 | 386 |
285 private: | 387 private: |
286 scoped_refptr<VideoFrame> frame_; | 388 scoped_refptr<VideoFrame> frame_; |
287 | 389 |
288 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); | 390 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); |
289 }; | 391 }; |
290 | 392 |
291 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 393 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
292 : generator_(NULL), last_frame_timestamp_(media::kNoTimestamp()) { | 394 : generator_(NULL), |
395 last_frame_timestamp_(media::kNoTimestamp()), | |
396 accelerated_last_frame_timestamp_(media::kNoTimestamp()) { | |
293 last_frame_.setIsVolatile(true); | 397 last_frame_.setIsVolatile(true); |
294 } | 398 } |
295 | 399 |
296 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 400 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
297 | 401 |
298 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, | 402 void SkCanvasVideoRenderer::Paint( |
299 SkCanvas* canvas, | 403 const scoped_refptr<VideoFrame>& video_frame, |
300 const gfx::RectF& dest_rect, | 404 SkCanvas* canvas, |
301 uint8 alpha, | 405 const gfx::RectF& dest_rect, |
302 SkXfermode::Mode mode, | 406 uint8 alpha, |
303 VideoRotation video_rotation) { | 407 SkXfermode::Mode mode, |
408 VideoRotation video_rotation, | |
409 SkCanvasVideoRenderer::Context3DProvider* context_provider) { | |
scherkus (not reviewing)
2014/10/15 17:10:23
we can drop SkCanvasVideoRenderer::, right?
| |
304 if (alpha == 0) { | 410 if (alpha == 0) { |
305 return; | 411 return; |
306 } | 412 } |
307 | 413 |
308 SkRect dest; | 414 SkRect dest; |
309 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 415 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
310 | 416 |
311 SkPaint paint; | 417 SkPaint paint; |
312 paint.setAlpha(alpha); | 418 paint.setAlpha(alpha); |
313 | 419 |
314 // Paint black rectangle if there isn't a frame available or the | 420 // Paint black rectangle if there isn't a frame available or the |
315 // frame has an unexpected format. | 421 // frame has an unexpected format. |
316 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { | 422 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || |
423 !IsYUVOrNative(video_frame->format())) { | |
317 canvas->drawRect(dest, paint); | 424 canvas->drawRect(dest, paint); |
318 canvas->flush(); | 425 canvas->flush(); |
319 return; | 426 return; |
320 } | 427 } |
321 | 428 |
429 bool accelerated = false; | |
430 if (!IsNull(context_provider) && | |
431 video_frame->format() == media::VideoFrame::NATIVE_TEXTURE && | |
432 canvas->getGrContext()) { | |
433 // TODO(dshwang): Android video decoder doesn't update the timestamp on a | |
434 // VideoFrame. To reduce redundant copy, Android should update the | |
435 // timestamp. | |
436 if (accelerated_last_frame_.isNull() || | |
437 video_frame->timestamp() != accelerated_last_frame_timestamp_ || | |
438 video_frame->timestamp() == base::TimeDelta()) { | |
439 accelerated = ConvertVideoFrameToTexture( | |
440 video_frame.get(), &accelerated_last_frame_, context_provider); | |
441 if (accelerated) | |
442 accelerated_last_frame_timestamp_ = video_frame->timestamp(); | |
443 } else { | |
444 DCHECK(accelerated_last_frame_.getTexture()); | |
445 accelerated = true; | |
446 } | |
447 } | |
448 | |
322 // Check if we should convert and update |last_frame_|. | 449 // Check if we should convert and update |last_frame_|. |
323 if (last_frame_.isNull() || | 450 if (!accelerated) { |
324 video_frame->timestamp() != last_frame_timestamp_) { | 451 if (last_frame_.isNull() || |
325 generator_ = new VideoImageGenerator(video_frame); | 452 video_frame->timestamp() != last_frame_timestamp_) { |
453 generator_ = new VideoImageGenerator(video_frame); | |
326 | 454 |
327 // Note: This takes ownership of |generator_|. | 455 // Note: This takes ownership of |generator_|. |
328 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { | 456 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { |
329 NOTREACHED(); | 457 NOTREACHED(); |
458 } | |
459 DCHECK(video_frame->visible_rect().width() == last_frame_.width() && | |
460 video_frame->visible_rect().height() == last_frame_.height()); | |
461 | |
462 last_frame_timestamp_ = video_frame->timestamp(); | |
463 } else if (generator_) { | |
464 generator_->set_frame(video_frame); | |
330 } | 465 } |
331 DCHECK(video_frame->visible_rect().width() == last_frame_.width() && | |
332 video_frame->visible_rect().height() == last_frame_.height()); | |
333 | |
334 last_frame_timestamp_ = video_frame->timestamp(); | |
335 } else if (generator_) { | |
336 generator_->set_frame(video_frame); | |
337 } | 466 } |
338 | 467 |
339 paint.setXfermodeMode(mode); | 468 paint.setXfermodeMode(mode); |
340 paint.setFilterLevel(SkPaint::kLow_FilterLevel); | 469 paint.setFilterLevel(SkPaint::kLow_FilterLevel); |
341 | 470 |
471 SkBitmap& target_frame = accelerated ? accelerated_last_frame_ : last_frame_; | |
342 bool need_transform = | 472 bool need_transform = |
343 video_rotation != VIDEO_ROTATION_0 || | 473 video_rotation != VIDEO_ROTATION_0 || |
344 dest_rect.size() != video_frame->visible_rect().size() || | 474 dest_rect.size() != video_frame->visible_rect().size() || |
345 !dest_rect.origin().IsOrigin(); | 475 !dest_rect.origin().IsOrigin(); |
346 if (need_transform) { | 476 if (need_transform) { |
347 canvas->save(); | 477 canvas->save(); |
348 canvas->translate( | 478 canvas->translate( |
349 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)), | 479 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)), |
350 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f))); | 480 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f))); |
351 SkScalar angle = SkFloatToScalar(0.0f); | 481 SkScalar angle = SkFloatToScalar(0.0f); |
(...skipping 12 matching lines...) Expand all Loading... | |
364 } | 494 } |
365 canvas->rotate(angle); | 495 canvas->rotate(angle); |
366 | 496 |
367 gfx::SizeF rotated_dest_size = dest_rect.size(); | 497 gfx::SizeF rotated_dest_size = dest_rect.size(); |
368 if (video_rotation == VIDEO_ROTATION_90 || | 498 if (video_rotation == VIDEO_ROTATION_90 || |
369 video_rotation == VIDEO_ROTATION_270) { | 499 video_rotation == VIDEO_ROTATION_270) { |
370 rotated_dest_size = | 500 rotated_dest_size = |
371 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 501 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
372 } | 502 } |
373 canvas->scale( | 503 canvas->scale( |
374 SkFloatToScalar(rotated_dest_size.width() / last_frame_.width()), | 504 SkFloatToScalar(rotated_dest_size.width() / target_frame.width()), |
375 SkFloatToScalar(rotated_dest_size.height() / last_frame_.height())); | 505 SkFloatToScalar(rotated_dest_size.height() / target_frame.height())); |
376 canvas->translate(-SkFloatToScalar(last_frame_.width() * 0.5f), | 506 canvas->translate(-SkFloatToScalar(target_frame.width() * 0.5f), |
377 -SkFloatToScalar(last_frame_.height() * 0.5f)); | 507 -SkFloatToScalar(target_frame.height() * 0.5f)); |
378 } | 508 } |
379 canvas->drawBitmap(last_frame_, 0, 0, &paint); | 509 canvas->drawBitmap(target_frame, 0, 0, &paint); |
380 if (need_transform) | 510 if (need_transform) |
381 canvas->restore(); | 511 canvas->restore(); |
382 canvas->flush(); | 512 canvas->flush(); |
383 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 513 // SkCanvas::flush() causes the generator to generate SkImage, so delete |
384 // |video_frame| not to be outlived. | 514 // |video_frame| not to be outlived. |
385 if (generator_) | 515 if (generator_) |
386 generator_->set_frame(NULL); | 516 generator_->set_frame(NULL); |
517 CleanUpTemporaryBuffers(); | |
387 } | 518 } |
388 | 519 |
389 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 520 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
390 SkCanvas* canvas) { | 521 SkCanvas* canvas) { |
391 Paint(video_frame, | 522 Paint(video_frame, |
392 canvas, | 523 canvas, |
393 video_frame->visible_rect(), | 524 video_frame->visible_rect(), |
394 0xff, | 525 0xff, |
395 SkXfermode::kSrc_Mode, | 526 SkXfermode::kSrc_Mode, |
396 media::VIDEO_ROTATION_0); | 527 media::VIDEO_ROTATION_0, |
528 NULL); | |
529 } | |
530 | |
531 void SkCanvasVideoRenderer::CleanUpTemporaryBuffers() { | |
532 static const base::TimeDelta buffer_time = | |
533 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay); | |
534 // Find the latest time stamp. | |
535 base::TimeDelta last_timestamp = | |
536 accelerated_last_frame_timestamp_ > last_frame_timestamp_ | |
537 ? accelerated_last_frame_timestamp_ | |
538 : last_frame_timestamp_; | |
539 // Delete a too old resource. | |
540 if (last_timestamp > last_frame_timestamp_ + buffer_time && | |
541 !last_frame_.isNull()) { | |
542 last_frame_.reset(); | |
543 } | |
544 if (last_timestamp > accelerated_last_frame_timestamp_ + buffer_time && | |
545 !accelerated_last_frame_.isNull()) { | |
546 accelerated_last_frame_.reset(); | |
547 } | |
548 } | |
549 | |
550 // static | |
551 void SkCanvasVideoRenderer::CopyVideoFrameToTexture( | |
scherkus (not reviewing)
2014/10/15 17:10:23
ditto for precise naming
this is much more like C
| |
552 gpu::gles2::GLES2Interface* gl, | |
553 VideoFrame* video_frame, | |
554 unsigned int texture, | |
555 unsigned int level, | |
556 unsigned int internal_format, | |
557 unsigned int type, | |
558 bool premultiply_alpha, | |
559 bool flip_y) { | |
560 DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE); | |
561 const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder(); | |
562 DCHECK(mailbox_holder->texture_target == GL_TEXTURE_2D || | |
563 mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES); | |
564 | |
565 gl->WaitSyncPointCHROMIUM(mailbox_holder->sync_point); | |
566 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM( | |
567 mailbox_holder->texture_target, mailbox_holder->mailbox.name); | |
568 | |
569 // The video is stored in a unmultiplied format, so premultiply | |
570 // if necessary. | |
571 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha); | |
572 // Application itself needs to take care of setting the right |flip_y| | |
573 // value down to get the expected result. | |
574 // "flip_y == true" means to reverse the video orientation while | |
575 // "flip_y == false" means to keep the intrinsic orientation. | |
576 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y); | |
577 gl->CopyTextureCHROMIUM( | |
578 GL_TEXTURE_2D, source_texture, texture, level, internal_format, type); | |
579 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); | |
580 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); | |
581 | |
582 gl->DeleteTextures(1, &source_texture); | |
583 gl->Flush(); | |
584 | |
585 SyncPointClientImpl client(gl); | |
586 video_frame->UpdateReleaseSyncPoint(&client); | |
397 } | 587 } |
398 | 588 |
399 } // namespace media | 589 } // namespace media |
OLD | NEW |