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 class SyncPointClientImpl : public VideoFrame::SyncPointClient { |
88 SkBitmap* bitmap, | 92 public: |
89 const Context3D& context_3d) { | 93 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} |
| 94 ~SyncPointClientImpl() override {} |
| 95 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } |
| 96 void WaitSyncPoint(uint32 sync_point) override { |
| 97 gl_->WaitSyncPointCHROMIUM(sync_point); |
| 98 } |
| 99 |
| 100 private: |
| 101 gpu::gles2::GLES2Interface* gl_; |
| 102 |
| 103 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); |
| 104 }; |
| 105 |
| 106 scoped_ptr<SkImage> CreateSkImageFromVideoFrameYUVTextures( |
| 107 VideoFrame* video_frame, |
| 108 const Context3D& context_3d) { |
| 109 // Support only TEXTURE_YUV_420. |
| 110 DCHECK(video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE); |
| 111 DCHECK_EQ(media::VideoFrame::I420, video_frame->format()); |
| 112 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format())); |
| 113 |
| 114 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
| 115 DCHECK(gl); |
| 116 gfx::Size ya_tex_size = video_frame->coded_size(); |
| 117 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2, |
| 118 (ya_tex_size.height() + 1) / 2); |
| 119 |
| 120 unsigned source_textures[3] = {0}; |
| 121 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); |
| 122 ++i) { |
| 123 // Get the texture from the mailbox and wrap it in a GrTexture. |
| 124 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i); |
| 125 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
| 126 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES || |
| 127 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB); |
| 128 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); |
| 129 source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM( |
| 130 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 131 } |
| 132 GrBackendObject handles[3] = { |
| 133 source_textures[0], source_textures[1], source_textures[2]}; |
| 134 |
| 135 SkISize yuvSizes[] = { |
| 136 {ya_tex_size.width(), ya_tex_size.height()}, |
| 137 {uv_tex_size.width(), uv_tex_size.height()}, |
| 138 {uv_tex_size.width(), uv_tex_size.height()}, |
| 139 }; |
| 140 |
| 141 // TODO(dcastagna): Skia currently doesn't support Rec709 YUV conversion. |
| 142 DCHECK(!CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_HD_REC709)); |
| 143 SkYUVColorSpace color_space = kRec601_SkYUVColorSpace; |
| 144 if (CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_JPEG)) |
| 145 color_space = kJPEG_SkYUVColorSpace; |
| 146 |
| 147 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context, |
| 148 color_space, handles, yuvSizes, |
| 149 kTopLeft_GrSurfaceOrigin); |
| 150 DCHECK(img); |
| 151 gl->DeleteTextures(3, source_textures); |
| 152 SyncPointClientImpl client(gl); |
| 153 video_frame->UpdateReleaseSyncPoint(&client); |
| 154 return make_scoped_ptr(img); |
| 155 } |
| 156 |
| 157 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, |
| 158 SkBitmap* bitmap, |
| 159 const Context3D& context_3d) { |
90 // Check if we could reuse existing texture based bitmap. | 160 // Check if we could reuse existing texture based bitmap. |
91 // Otherwise, release existing texture based bitmap and allocate | 161 // Otherwise, release existing texture based bitmap and allocate |
92 // a new one based on video size. | 162 // a new one based on video size. |
93 if (!IsSkBitmapProperlySizedTexture(bitmap, | 163 if (!IsSkBitmapProperlySizedTexture(bitmap, |
94 video_frame->visible_rect().size())) { | 164 video_frame->visible_rect().size())) { |
95 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, | 165 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, |
96 video_frame->visible_rect().size())) { | 166 video_frame->visible_rect().size())) { |
97 return false; | 167 return false; |
98 } | 168 } |
99 } | 169 } |
100 | 170 |
101 unsigned texture_id = | 171 unsigned texture_id = |
102 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); | 172 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); |
103 // If CopyVideoFrameTextureToGLTexture() changes the state of the | 173 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the |
104 // |texture_id|, it's needed to invalidate the state cached in skia, | 174 // |texture_id|, it's needed to invalidate the state cached in skia, |
105 // but currently the state isn't changed. | 175 // but currently the state isn't changed. |
106 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 176 |
| 177 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
107 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, | 178 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, |
108 false); | 179 false); |
109 bitmap->notifyPixelsChanged(); | 180 bitmap->notifyPixelsChanged(); |
110 return true; | 181 return true; |
111 } | 182 } |
112 | 183 |
113 class SyncPointClientImpl : public VideoFrame::SyncPointClient { | |
114 public: | |
115 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} | |
116 ~SyncPointClientImpl() override {} | |
117 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } | |
118 void WaitSyncPoint(uint32 sync_point) override { | |
119 gl_->WaitSyncPointCHROMIUM(sync_point); | |
120 } | |
121 | |
122 private: | |
123 gpu::gles2::GLES2Interface* gl_; | |
124 | |
125 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); | |
126 }; | |
127 | |
128 } // anonymous namespace | 184 } // anonymous namespace |
129 | 185 |
130 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. | 186 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. |
131 class VideoImageGenerator : public SkImageGenerator { | 187 class VideoImageGenerator : public SkImageGenerator { |
132 public: | 188 public: |
133 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) | 189 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) |
134 : SkImageGenerator( | 190 : SkImageGenerator( |
135 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), | 191 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), |
136 frame->visible_rect().height())) | 192 frame->visible_rect().height())) |
137 , frame_(frame) { | 193 , frame_(frame) { |
(...skipping 145 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. | 339 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. |
284 if (accelerated_last_frame_.isNull() || | 340 if (accelerated_last_frame_.isNull() || |
285 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 341 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
286 DCHECK(context_3d.gl); | 342 DCHECK(context_3d.gl); |
287 DCHECK(context_3d.gr_context); | 343 DCHECK(context_3d.gr_context); |
288 if (accelerated_generator_) { | 344 if (accelerated_generator_) { |
289 // Reset SkBitmap used in SWVideo-to-HWCanvas path. | 345 // Reset SkBitmap used in SWVideo-to-HWCanvas path. |
290 accelerated_last_frame_.reset(); | 346 accelerated_last_frame_.reset(); |
291 accelerated_generator_ = nullptr; | 347 accelerated_generator_ = nullptr; |
292 } | 348 } |
293 if (!CopyVideoFrameTextureToSkBitmapTexture( | 349 |
294 video_frame.get(), &accelerated_last_frame_, context_3d)) { | 350 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { |
295 NOTREACHED(); | 351 accelerated_last_image_.reset(); |
296 return; | 352 if (!CopyVideoFrameSingleTextureToSkBitmap( |
| 353 video_frame.get(), &accelerated_last_frame_, context_3d)) { |
| 354 NOTREACHED(); |
| 355 return; |
| 356 } |
| 357 DCHECK(video_frame->visible_rect().width() == |
| 358 accelerated_last_frame_.width() && |
| 359 video_frame->visible_rect().height() == |
| 360 accelerated_last_frame_.height()); |
| 361 } else { |
| 362 accelerated_last_image_ = CreateSkImageFromVideoFrameYUVTextures( |
| 363 video_frame.get(), context_3d); |
| 364 DCHECK(accelerated_last_image_); |
297 } | 365 } |
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(); | 366 accelerated_last_frame_timestamp_ = video_frame->timestamp(); |
304 } | 367 } |
305 target_frame = &accelerated_last_frame_; | 368 target_frame = &accelerated_last_frame_; |
306 accelerated_frame_deleting_timer_.Reset(); | 369 accelerated_frame_deleting_timer_.Reset(); |
307 } else if (canvas->getGrContext()) { | 370 } else if (canvas->getGrContext()) { |
308 if (accelerated_last_frame_.isNull() || | 371 if (accelerated_last_frame_.isNull() || |
309 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 372 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
310 // Draw SW Video on HW Canvas. | 373 // Draw SW Video on HW Canvas. |
311 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { | 374 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { |
312 // Reset SkBitmap used in HWVideo-to-HWCanvas path. | 375 // 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) { | 451 video_rotation == VIDEO_ROTATION_270) { |
389 rotated_dest_size = | 452 rotated_dest_size = |
390 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 453 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
391 } | 454 } |
392 canvas->scale( | 455 canvas->scale( |
393 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), | 456 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), |
394 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); | 457 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); |
395 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), | 458 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
396 -SkFloatToScalar(target_frame->height() * 0.5f)); | 459 -SkFloatToScalar(target_frame->height() * 0.5f)); |
397 } | 460 } |
398 canvas->drawBitmap(*target_frame, 0, 0, &paint); | 461 if (accelerated_last_image_) { |
| 462 canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); |
| 463 } else { |
| 464 canvas->drawBitmap(*target_frame, 0, 0, &paint); |
| 465 } |
399 if (need_transform) | 466 if (need_transform) |
400 canvas->restore(); | 467 canvas->restore(); |
401 canvas->flush(); | 468 canvas->flush(); |
402 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 469 // SkCanvas::flush() causes the generator to generate SkImage, so delete |
403 // |video_frame| not to be outlived. | 470 // |video_frame| not to be outlived. |
404 if (canvas->getGrContext() && accelerated_generator_) | 471 if (canvas->getGrContext() && accelerated_generator_) |
405 accelerated_generator_->set_frame(nullptr); | 472 accelerated_generator_->set_frame(nullptr); |
406 } | 473 } |
407 | 474 |
408 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 475 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: | 608 case VideoFrame::NV12: |
542 #endif | 609 #endif |
543 case VideoFrame::ARGB: | 610 case VideoFrame::ARGB: |
544 case VideoFrame::XRGB: | 611 case VideoFrame::XRGB: |
545 case VideoFrame::UNKNOWN: | 612 case VideoFrame::UNKNOWN: |
546 NOTREACHED(); | 613 NOTREACHED(); |
547 } | 614 } |
548 } | 615 } |
549 | 616 |
550 // static | 617 // static |
551 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 618 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
552 gpu::gles2::GLES2Interface* gl, | 619 gpu::gles2::GLES2Interface* gl, |
553 VideoFrame* video_frame, | 620 VideoFrame* video_frame, |
554 unsigned int texture, | 621 unsigned int texture, |
555 unsigned int internal_format, | 622 unsigned int internal_format, |
556 unsigned int type, | 623 unsigned int type, |
557 bool premultiply_alpha, | 624 bool premultiply_alpha, |
558 bool flip_y) { | 625 bool flip_y) { |
559 DCHECK(video_frame); | 626 DCHECK(video_frame); |
560 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); | 627 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); |
561 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); | 628 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); |
(...skipping 26 matching lines...) Expand all Loading... |
588 SyncPointClientImpl client(gl); | 655 SyncPointClientImpl client(gl); |
589 video_frame->UpdateReleaseSyncPoint(&client); | 656 video_frame->UpdateReleaseSyncPoint(&client); |
590 } | 657 } |
591 | 658 |
592 void SkCanvasVideoRenderer::ResetLastFrame() { | 659 void SkCanvasVideoRenderer::ResetLastFrame() { |
593 last_frame_.reset(); | 660 last_frame_.reset(); |
594 last_frame_timestamp_ = media::kNoTimestamp(); | 661 last_frame_timestamp_ = media::kNoTimestamp(); |
595 } | 662 } |
596 | 663 |
597 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { | 664 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { |
| 665 accelerated_last_image_.reset(); |
598 accelerated_last_frame_.reset(); | 666 accelerated_last_frame_.reset(); |
599 accelerated_generator_ = nullptr; | 667 accelerated_generator_ = nullptr; |
600 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); | 668 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); |
601 } | 669 } |
602 | 670 |
603 } // namespace media | 671 } // namespace media |
OLD | NEW |