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/renderers/skcanvas_video_renderer.h" | 5 #include "media/renderers/skcanvas_video_renderer.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 10 #include "gpu/GLES2/gl2extchromium.h" |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 // frame has an unexpected format. | 351 // frame has an unexpected format. |
352 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || | 352 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || |
353 !(media::IsYuvPlanar(video_frame->format()) || | 353 !(media::IsYuvPlanar(video_frame->format()) || |
354 video_frame->HasTextures())) { | 354 video_frame->HasTextures())) { |
355 canvas->drawRect(dest, paint); | 355 canvas->drawRect(dest, paint); |
356 canvas->flush(); | 356 canvas->flush(); |
357 return; | 357 return; |
358 } | 358 } |
359 | 359 |
360 gpu::gles2::GLES2Interface* gl = context_3d.gl; | 360 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
361 | 361 if (!UpdateLastImage(video_frame, context_3d)) |
362 if (!last_image_ || video_frame->timestamp() != last_timestamp_) { | 362 return; |
363 ResetCache(); | |
364 // Generate a new image. | |
365 // Note: Skia will hold onto |video_frame| via |video_generator| only when | |
366 // |video_frame| is software. | |
367 // Holding |video_frame| longer than this call when using GPUVideoDecoder | |
368 // could cause problems since the pool of VideoFrames has a fixed size. | |
369 if (video_frame->HasTextures()) { | |
370 DCHECK(context_3d.gr_context); | |
371 DCHECK(gl); | |
372 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { | |
373 last_image_ = | |
374 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d); | |
375 } else { | |
376 last_image_ = | |
377 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d); | |
378 } | |
379 } else { | |
380 auto* video_generator = new VideoImageGenerator(video_frame); | |
381 last_image_ = SkImage::MakeFromGenerator(video_generator); | |
382 } | |
383 if (!last_image_) // Couldn't create the SkImage. | |
384 return; | |
385 last_timestamp_ = video_frame->timestamp(); | |
386 } | |
387 last_image_deleting_timer_.Reset(); | |
388 | 363 |
389 paint.setXfermodeMode(mode); | 364 paint.setXfermodeMode(mode); |
390 paint.setFilterQuality(kLow_SkFilterQuality); | 365 paint.setFilterQuality(kLow_SkFilterQuality); |
391 | 366 |
392 const bool need_rotation = video_rotation != VIDEO_ROTATION_0; | 367 const bool need_rotation = video_rotation != VIDEO_ROTATION_0; |
393 const bool need_scaling = | 368 const bool need_scaling = |
394 dest_rect.size() != | 369 dest_rect.size() != |
395 gfx::SizeF(gfx::SkISizeToSize(last_image_->dimensions())); | 370 gfx::SizeF(gfx::SkISizeToSize(last_image_->dimensions())); |
396 const bool need_translation = !dest_rect.origin().IsOrigin(); | 371 const bool need_translation = !dest_rect.origin().IsOrigin(); |
397 bool need_transform = need_rotation || need_scaling || need_translation; | 372 bool need_transform = need_rotation || need_scaling || need_translation; |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 // "flip_y == false" means to keep the intrinsic orientation. | 639 // "flip_y == false" means to keep the intrinsic orientation. |
665 gl->CopyTextureCHROMIUM(source_texture, texture, internal_format, type, | 640 gl->CopyTextureCHROMIUM(source_texture, texture, internal_format, type, |
666 flip_y, premultiply_alpha, false); | 641 flip_y, premultiply_alpha, false); |
667 gl->DeleteTextures(1, &source_texture); | 642 gl->DeleteTextures(1, &source_texture); |
668 gl->Flush(); | 643 gl->Flush(); |
669 | 644 |
670 SyncTokenClientImpl client(gl); | 645 SyncTokenClientImpl client(gl); |
671 video_frame->UpdateReleaseSyncToken(&client); | 646 video_frame->UpdateReleaseSyncToken(&client); |
672 } | 647 } |
673 | 648 |
| 649 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
| 650 const Context3D& context_3d, |
| 651 gpu::gles2::GLES2Interface* destination_gl, |
| 652 const scoped_refptr<VideoFrame>& video_frame, |
| 653 unsigned int texture, |
| 654 unsigned int internal_format, |
| 655 unsigned int type, |
| 656 bool premultiply_alpha, |
| 657 bool flip_y) { |
| 658 DCHECK(thread_checker_.CalledOnValidThread()); |
| 659 DCHECK(video_frame); |
| 660 DCHECK(video_frame->HasTextures()); |
| 661 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { |
| 662 if (!context_3d.gr_context) |
| 663 return false; |
| 664 if (!UpdateLastImage(video_frame, context_3d)) |
| 665 return false; |
| 666 |
| 667 const GrGLTextureInfo* texture_info = |
| 668 skia::GrBackendObjectToGrGLTextureInfo( |
| 669 last_image_->getTextureHandle(true)); |
| 670 |
| 671 gpu::gles2::GLES2Interface* canvas_gl = context_3d.gl; |
| 672 gpu::MailboxHolder mailbox_holder; |
| 673 mailbox_holder.texture_target = texture_info->fTarget; |
| 674 canvas_gl->GenMailboxCHROMIUM(mailbox_holder.mailbox.name); |
| 675 canvas_gl->ProduceTextureDirectCHROMIUM(texture_info->fID, |
| 676 mailbox_holder.texture_target, |
| 677 mailbox_holder.mailbox.name); |
| 678 |
| 679 // Wait for mailbox creation on canvas context before consuming it and |
| 680 // copying from it on the consumer context. |
| 681 const GLuint64 fence_sync = canvas_gl->InsertFenceSyncCHROMIUM(); |
| 682 canvas_gl->ShallowFlushCHROMIUM(); |
| 683 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, |
| 684 mailbox_holder.sync_token.GetData()); |
| 685 |
| 686 destination_gl->WaitSyncTokenCHROMIUM( |
| 687 mailbox_holder.sync_token.GetConstData()); |
| 688 uint32_t intermediate_texture = |
| 689 destination_gl->CreateAndConsumeTextureCHROMIUM( |
| 690 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 691 |
| 692 destination_gl->CopyTextureCHROMIUM(intermediate_texture, texture, |
| 693 internal_format, type, flip_y, |
| 694 premultiply_alpha, false); |
| 695 destination_gl->DeleteTextures(1, &intermediate_texture); |
| 696 |
| 697 // Wait for destination context to consume mailbox before deleting it in |
| 698 // canvas context. |
| 699 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); |
| 700 destination_gl->ShallowFlushCHROMIUM(); |
| 701 gpu::SyncToken dest_sync_token; |
| 702 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, |
| 703 dest_sync_token.GetData()); |
| 704 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); |
| 705 |
| 706 SyncTokenClientImpl client(canvas_gl); |
| 707 video_frame->UpdateReleaseSyncToken(&client); |
| 708 } else { |
| 709 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), |
| 710 texture, internal_format, type, |
| 711 premultiply_alpha, flip_y); |
| 712 } |
| 713 |
| 714 return true; |
| 715 } |
| 716 |
674 void SkCanvasVideoRenderer::ResetCache() { | 717 void SkCanvasVideoRenderer::ResetCache() { |
675 DCHECK(thread_checker_.CalledOnValidThread()); | 718 DCHECK(thread_checker_.CalledOnValidThread()); |
676 // Clear cached values. | 719 // Clear cached values. |
677 last_image_ = nullptr; | 720 last_image_ = nullptr; |
678 last_timestamp_ = kNoTimestamp; | 721 last_timestamp_ = kNoTimestamp; |
679 } | 722 } |
680 | 723 |
| 724 bool SkCanvasVideoRenderer::UpdateLastImage( |
| 725 const scoped_refptr<VideoFrame>& video_frame, |
| 726 const Context3D& context_3d) { |
| 727 if (!last_image_ || video_frame->timestamp() != last_timestamp_) { |
| 728 ResetCache(); |
| 729 // Generate a new image. |
| 730 // Note: Skia will hold onto |video_frame| via |video_generator| only when |
| 731 // |video_frame| is software. |
| 732 // Holding |video_frame| longer than this call when using GPUVideoDecoder |
| 733 // could cause problems since the pool of VideoFrames has a fixed size. |
| 734 if (video_frame->HasTextures()) { |
| 735 DCHECK(context_3d.gr_context); |
| 736 DCHECK(context_3d.gl); |
| 737 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { |
| 738 last_image_ = |
| 739 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d); |
| 740 } else { |
| 741 last_image_ = |
| 742 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d); |
| 743 } |
| 744 } else { |
| 745 auto* video_generator = new VideoImageGenerator(video_frame); |
| 746 last_image_ = SkImage::MakeFromGenerator(video_generator); |
| 747 } |
| 748 if (!last_image_) // Couldn't create the SkImage. |
| 749 return false; |
| 750 last_timestamp_ = video_frame->timestamp(); |
| 751 } |
| 752 last_image_deleting_timer_.Reset(); |
| 753 DCHECK(!!last_image_); |
| 754 return true; |
| 755 } |
| 756 |
681 } // namespace media | 757 } // namespace media |
OLD | NEW |