Chromium Code Reviews| 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/blink/skcanvas_video_renderer.h" | 5 #include "media/blink/skcanvas_video_renderer.h" |
| 6 | 6 |
| 7 #include "gpu/GLES2/gl2extchromium.h" | 7 #include "gpu/GLES2/gl2extchromium.h" |
| 8 #include "gpu/command_buffer/client/gles2_interface.h" | 8 #include "gpu/command_buffer/client/gles2_interface.h" |
| 9 #include "gpu/command_buffer/common/mailbox_holder.h" | 9 #include "gpu/command_buffer/common/mailbox_holder.h" |
| 10 #include "media/base/video_frame.h" | 10 #include "media/base/video_frame.h" |
| 11 #include "media/base/yuv_convert.h" | 11 #include "media/base/yuv_convert.h" |
| 12 #include "skia/ext/refptr.h" | 12 #include "skia/ext/refptr.h" |
| 13 #include "third_party/libyuv/include/libyuv.h" | 13 #include "third_party/libyuv/include/libyuv.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" | 14 #include "third_party/skia/include/core/SkCanvas.h" |
| 15 #include "third_party/skia/include/core/SkImage.h" | |
| 15 #include "third_party/skia/include/core/SkImageGenerator.h" | 16 #include "third_party/skia/include/core/SkImageGenerator.h" |
| 16 #include "third_party/skia/include/gpu/GrContext.h" | 17 #include "third_party/skia/include/gpu/GrContext.h" |
| 18 #include "third_party/skia/include/gpu/GrPaint.h" | |
| 19 #include "third_party/skia/include/gpu/GrTexture.h" | |
| 17 #include "third_party/skia/include/gpu/GrTextureProvider.h" | 20 #include "third_party/skia/include/gpu/GrTextureProvider.h" |
| 21 #include "third_party/skia/include/gpu/SkGr.h" | |
| 18 #include "third_party/skia/include/gpu/SkGrPixelRef.h" | 22 #include "third_party/skia/include/gpu/SkGrPixelRef.h" |
| 19 #include "ui/gfx/skbitmap_operations.h" | 23 #include "ui/gfx/skbitmap_operations.h" |
| 20 | 24 |
| 21 // Skia internal format depends on a platform. On Android it is ABGR, on others | 25 // Skia internal format depends on a platform. On Android it is ABGR, on others |
| 22 // it is ARGB. | 26 // it is ARGB. |
| 23 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ | 27 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ |
| 24 SK_A32_SHIFT == 24 | 28 SK_A32_SHIFT == 24 |
| 25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB | 29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB |
| 26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB | 30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB |
| 27 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ | 31 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 | 81 |
| 78 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight); | 82 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight); |
| 79 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get())); | 83 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get())); |
| 80 if (!pixel_ref) | 84 if (!pixel_ref) |
| 81 return false; | 85 return false; |
| 82 bitmap->setInfo(info); | 86 bitmap->setInfo(info); |
| 83 bitmap->setPixelRef(pixel_ref)->unref(); | 87 bitmap->setPixelRef(pixel_ref)->unref(); |
| 84 return true; | 88 return true; |
| 85 } | 89 } |
| 86 | 90 |
| 87 bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame, | 91 scoped_ptr<SkImage> CreateSkImageFromVideoFrameNativeTextures( |
| 88 SkBitmap* bitmap, | 92 VideoFrame* video_frame, |
| 89 const Context3D& context_3d) { | 93 const Context3D& context_3d) { |
| 94 // Support only TEXTURE_YUV_420. | |
| 95 DCHECK(video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE); | |
| 96 DCHECK_EQ(media::VideoFrame::I420, video_frame->format()); | |
| 97 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format())); | |
| 98 | |
| 99 gpu::gles2::GLES2Interface* gl = context_3d.gl; | |
| 100 gfx::Size ya_tex_size = video_frame->coded_size(); | |
| 101 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2, | |
| 102 (ya_tex_size.height() + 1) / 2); | |
| 103 | |
| 104 unsigned source_textures[3] = {0}; | |
| 105 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); | |
| 106 ++i) { | |
| 107 // Get the texture from the mailbox and wrap it in a GrTexture. | |
| 108 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i); | |
| 109 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | |
| 110 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB); | |
|
dshwang
2015/06/10 07:26:37
TEXTURE_EXTERNAL_OES?
Daniele Castagna
2015/06/10 14:22:54
Done.
| |
| 111 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); | |
| 112 source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM( | |
| 113 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | |
|
dshwang
2015/06/10 07:26:38
how these textures are deleted?
Daniele Castagna
2015/06/10 14:22:54
Added glDeleteTextures.
| |
| 114 } | |
| 115 GrBackendObject handles[3] = { | |
| 116 source_textures[0], source_textures[1], source_textures[2]}; | |
| 117 | |
| 118 SkISize yuvSizes[] = { | |
| 119 {ya_tex_size.width(), ya_tex_size.height()}, | |
| 120 {uv_tex_size.width(), uv_tex_size.height()}, | |
| 121 {uv_tex_size.width(), uv_tex_size.height()}, | |
| 122 }; | |
| 123 SkImage* img = SkImage::NewFromYUVTexturesCopy( | |
| 124 context_3d.gr_context, kRec601_SkYUVColorSpace, handles, yuvSizes, | |
| 125 kTopLeft_GrSurfaceOrigin); | |
|
dshwang
2015/06/10 07:26:38
need to insert sync point here
Daniele Castagna
2015/06/10 14:22:54
Done.
| |
| 126 DCHECK(img); | |
| 127 return make_scoped_ptr(img); | |
| 128 } | |
| 129 | |
| 130 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, | |
| 131 SkBitmap* bitmap, | |
| 132 const Context3D& context_3d) { | |
| 90 // Check if we could reuse existing texture based bitmap. | 133 // Check if we could reuse existing texture based bitmap. |
| 91 // Otherwise, release existing texture based bitmap and allocate | 134 // Otherwise, release existing texture based bitmap and allocate |
| 92 // a new one based on video size. | 135 // a new one based on video size. |
| 93 if (!IsSkBitmapProperlySizedTexture(bitmap, | 136 if (!IsSkBitmapProperlySizedTexture(bitmap, |
| 94 video_frame->visible_rect().size())) { | 137 video_frame->visible_rect().size())) { |
| 95 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, | 138 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, |
| 96 video_frame->visible_rect().size())) { | 139 video_frame->visible_rect().size())) { |
| 97 return false; | 140 return false; |
| 98 } | 141 } |
| 99 } | 142 } |
| 100 | 143 |
| 101 unsigned texture_id = | 144 unsigned texture_id = |
| 102 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); | 145 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); |
| 103 // If CopyVideoFrameTextureToGLTexture() changes the state of the | 146 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the |
| 104 // |texture_id|, it's needed to invalidate the state cached in skia, | 147 // |texture_id|, it's needed to invalidate the state cached in skia, |
| 105 // but currently the state isn't changed. | 148 // but currently the state isn't changed. |
| 106 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 149 |
| 150 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | |
| 107 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, | 151 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, |
| 108 false); | 152 false); |
| 109 bitmap->notifyPixelsChanged(); | 153 bitmap->notifyPixelsChanged(); |
| 110 return true; | 154 return true; |
| 111 } | 155 } |
| 112 | 156 |
| 113 class SyncPointClientImpl : public VideoFrame::SyncPointClient { | 157 class SyncPointClientImpl : public VideoFrame::SyncPointClient { |
| 114 public: | 158 public: |
| 115 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} | 159 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} |
| 116 ~SyncPointClientImpl() override {} | 160 ~SyncPointClientImpl() override {} |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. | 327 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. |
| 284 if (accelerated_last_frame_.isNull() || | 328 if (accelerated_last_frame_.isNull() || |
| 285 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 329 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
| 286 DCHECK(context_3d.gl); | 330 DCHECK(context_3d.gl); |
| 287 DCHECK(context_3d.gr_context); | 331 DCHECK(context_3d.gr_context); |
| 288 if (accelerated_generator_) { | 332 if (accelerated_generator_) { |
| 289 // Reset SkBitmap used in SWVideo-to-HWCanvas path. | 333 // Reset SkBitmap used in SWVideo-to-HWCanvas path. |
| 290 accelerated_last_frame_.reset(); | 334 accelerated_last_frame_.reset(); |
| 291 accelerated_generator_ = nullptr; | 335 accelerated_generator_ = nullptr; |
| 292 } | 336 } |
| 293 if (!CopyVideoFrameTextureToSkBitmapTexture( | 337 |
| 294 video_frame.get(), &accelerated_last_frame_, context_3d)) { | 338 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { |
| 295 NOTREACHED(); | 339 accelerated_last_image_.reset(); |
| 296 return; | 340 if (!CopyVideoFrameSingleTextureToSkBitmap( |
| 341 video_frame.get(), &accelerated_last_frame_, context_3d)) { | |
| 342 NOTREACHED(); | |
| 343 return; | |
| 344 } | |
| 345 DCHECK(video_frame->visible_rect().width() == | |
| 346 accelerated_last_frame_.width() && | |
| 347 video_frame->visible_rect().height() == | |
| 348 accelerated_last_frame_.height()); | |
| 349 } else { | |
| 350 accelerated_last_image_ = CreateSkImageFromVideoFrameNativeTextures( | |
| 351 video_frame.get(), context_3d); | |
| 352 DCHECK(accelerated_last_image_); | |
| 297 } | 353 } |
| 298 DCHECK(video_frame->visible_rect().width() == | |
| 299 accelerated_last_frame_.width() && | |
| 300 video_frame->visible_rect().height() == | |
| 301 accelerated_last_frame_.height()); | |
| 302 | |
| 303 accelerated_last_frame_timestamp_ = video_frame->timestamp(); | 354 accelerated_last_frame_timestamp_ = video_frame->timestamp(); |
| 304 } | 355 } |
| 305 target_frame = &accelerated_last_frame_; | 356 target_frame = &accelerated_last_frame_; |
| 306 accelerated_frame_deleting_timer_.Reset(); | 357 accelerated_frame_deleting_timer_.Reset(); |
| 307 } else if (canvas->getGrContext()) { | 358 } else if (canvas->getGrContext()) { |
| 308 if (accelerated_last_frame_.isNull() || | 359 if (accelerated_last_frame_.isNull() || |
| 309 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 360 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
| 310 // Draw SW Video on HW Canvas. | 361 // Draw SW Video on HW Canvas. |
| 311 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { | 362 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { |
| 312 // Reset SkBitmap used in HWVideo-to-HWCanvas path. | 363 // Reset SkBitmap used in HWVideo-to-HWCanvas path. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 video_rotation == VIDEO_ROTATION_270) { | 439 video_rotation == VIDEO_ROTATION_270) { |
| 389 rotated_dest_size = | 440 rotated_dest_size = |
| 390 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 441 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
| 391 } | 442 } |
| 392 canvas->scale( | 443 canvas->scale( |
| 393 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), | 444 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), |
| 394 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); | 445 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); |
| 395 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), | 446 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
| 396 -SkFloatToScalar(target_frame->height() * 0.5f)); | 447 -SkFloatToScalar(target_frame->height() * 0.5f)); |
| 397 } | 448 } |
| 398 canvas->drawBitmap(*target_frame, 0, 0, &paint); | 449 if (accelerated_last_image_) { |
| 450 canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); | |
| 451 } else { | |
| 452 canvas->drawBitmap(*target_frame, 0, 0, &paint); | |
| 453 } | |
| 399 if (need_transform) | 454 if (need_transform) |
| 400 canvas->restore(); | 455 canvas->restore(); |
| 401 canvas->flush(); | 456 canvas->flush(); |
| 402 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 457 // SkCanvas::flush() causes the generator to generate SkImage, so delete |
| 403 // |video_frame| not to be outlived. | 458 // |video_frame| not to be outlived. |
| 404 if (canvas->getGrContext() && accelerated_generator_) | 459 if (canvas->getGrContext() && accelerated_generator_) |
| 405 accelerated_generator_->set_frame(nullptr); | 460 accelerated_generator_->set_frame(nullptr); |
| 406 } | 461 } |
| 407 | 462 |
| 408 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 463 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 case VideoFrame::NV12: | 596 case VideoFrame::NV12: |
| 542 #endif | 597 #endif |
| 543 case VideoFrame::ARGB: | 598 case VideoFrame::ARGB: |
| 544 case VideoFrame::XRGB: | 599 case VideoFrame::XRGB: |
| 545 case VideoFrame::UNKNOWN: | 600 case VideoFrame::UNKNOWN: |
| 546 NOTREACHED(); | 601 NOTREACHED(); |
| 547 } | 602 } |
| 548 } | 603 } |
| 549 | 604 |
| 550 // static | 605 // static |
| 551 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 606 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| 552 gpu::gles2::GLES2Interface* gl, | 607 gpu::gles2::GLES2Interface* gl, |
| 553 VideoFrame* video_frame, | 608 VideoFrame* video_frame, |
| 554 unsigned int texture, | 609 unsigned int texture, |
| 555 unsigned int internal_format, | 610 unsigned int internal_format, |
| 556 unsigned int type, | 611 unsigned int type, |
| 557 bool premultiply_alpha, | 612 bool premultiply_alpha, |
| 558 bool flip_y) { | 613 bool flip_y) { |
| 559 DCHECK(video_frame); | 614 DCHECK(video_frame); |
| 560 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); | 615 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); |
| 561 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); | 616 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 588 SyncPointClientImpl client(gl); | 643 SyncPointClientImpl client(gl); |
| 589 video_frame->UpdateReleaseSyncPoint(&client); | 644 video_frame->UpdateReleaseSyncPoint(&client); |
| 590 } | 645 } |
| 591 | 646 |
| 592 void SkCanvasVideoRenderer::ResetLastFrame() { | 647 void SkCanvasVideoRenderer::ResetLastFrame() { |
| 593 last_frame_.reset(); | 648 last_frame_.reset(); |
| 594 last_frame_timestamp_ = media::kNoTimestamp(); | 649 last_frame_timestamp_ = media::kNoTimestamp(); |
| 595 } | 650 } |
| 596 | 651 |
| 597 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { | 652 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { |
| 653 accelerated_last_image_.reset(); | |
| 598 accelerated_last_frame_.reset(); | 654 accelerated_last_frame_.reset(); |
| 599 accelerated_generator_ = nullptr; | 655 accelerated_generator_ = nullptr; |
| 600 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); | 656 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); |
| 601 } | 657 } |
| 602 | 658 |
| 603 } // namespace media | 659 } // namespace media |
| OLD | NEW |