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> CreateSkImageFromVideoFrameNativeTextures( | |
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 SkImage* img = SkImage::NewFromYUVTexturesCopy( | |
141 context_3d.gr_context, kRec601_SkYUVColorSpace, handles, yuvSizes, | |
142 kTopLeft_GrSurfaceOrigin); | |
143 DCHECK(img); | |
144 gl->DeleteTextures(3, source_textures); | |
145 SyncPointClientImpl client(gl); | |
146 video_frame->UpdateReleaseSyncPoint(&client); | |
147 return make_scoped_ptr(img); | |
148 } | |
149 | |
150 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, | |
151 SkBitmap* bitmap, | |
152 const Context3D& context_3d) { | |
90 // Check if we could reuse existing texture based bitmap. | 153 // Check if we could reuse existing texture based bitmap. |
91 // Otherwise, release existing texture based bitmap and allocate | 154 // Otherwise, release existing texture based bitmap and allocate |
92 // a new one based on video size. | 155 // a new one based on video size. |
93 if (!IsSkBitmapProperlySizedTexture(bitmap, | 156 if (!IsSkBitmapProperlySizedTexture(bitmap, |
94 video_frame->visible_rect().size())) { | 157 video_frame->visible_rect().size())) { |
95 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, | 158 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, |
96 video_frame->visible_rect().size())) { | 159 video_frame->visible_rect().size())) { |
97 return false; | 160 return false; |
98 } | 161 } |
99 } | 162 } |
100 | 163 |
101 unsigned texture_id = | 164 unsigned texture_id = |
102 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); | 165 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); |
103 // If CopyVideoFrameTextureToGLTexture() changes the state of the | 166 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the |
104 // |texture_id|, it's needed to invalidate the state cached in skia, | 167 // |texture_id|, it's needed to invalidate the state cached in skia, |
105 // but currently the state isn't changed. | 168 // but currently the state isn't changed. |
106 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 169 |
170 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | |
107 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, | 171 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, |
108 false); | 172 false); |
109 bitmap->notifyPixelsChanged(); | 173 bitmap->notifyPixelsChanged(); |
110 return true; | 174 return true; |
111 } | 175 } |
112 | 176 |
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 | 177 } // anonymous namespace |
129 | 178 |
130 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. | 179 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. |
131 class VideoImageGenerator : public SkImageGenerator { | 180 class VideoImageGenerator : public SkImageGenerator { |
132 public: | 181 public: |
133 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) | 182 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) |
134 : SkImageGenerator( | 183 : SkImageGenerator( |
135 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), | 184 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), |
136 frame->visible_rect().height())) | 185 frame->visible_rect().height())) |
137 , frame_(frame) { | 186 , 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. | 332 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. |
284 if (accelerated_last_frame_.isNull() || | 333 if (accelerated_last_frame_.isNull() || |
285 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 334 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
286 DCHECK(context_3d.gl); | 335 DCHECK(context_3d.gl); |
287 DCHECK(context_3d.gr_context); | 336 DCHECK(context_3d.gr_context); |
288 if (accelerated_generator_) { | 337 if (accelerated_generator_) { |
289 // Reset SkBitmap used in SWVideo-to-HWCanvas path. | 338 // Reset SkBitmap used in SWVideo-to-HWCanvas path. |
290 accelerated_last_frame_.reset(); | 339 accelerated_last_frame_.reset(); |
291 accelerated_generator_ = nullptr; | 340 accelerated_generator_ = nullptr; |
292 } | 341 } |
293 if (!CopyVideoFrameTextureToSkBitmapTexture( | 342 |
294 video_frame.get(), &accelerated_last_frame_, context_3d)) { | 343 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { |
295 NOTREACHED(); | 344 accelerated_last_image_.reset(); |
296 return; | 345 if (!CopyVideoFrameSingleTextureToSkBitmap( |
346 video_frame.get(), &accelerated_last_frame_, context_3d)) { | |
347 NOTREACHED(); | |
348 return; | |
349 } | |
350 DCHECK(video_frame->visible_rect().width() == | |
351 accelerated_last_frame_.width() && | |
352 video_frame->visible_rect().height() == | |
353 accelerated_last_frame_.height()); | |
354 } else { | |
355 accelerated_last_image_ = CreateSkImageFromVideoFrameNativeTextures( | |
dshwang
2015/06/10 17:38:37
I'm not good at naming but I think the function na
Daniele Castagna
2015/06/10 17:42:34
How do you like CreateSkImageFromVideoFrameYUVText
dshwang
2015/06/10 17:45:05
I buy it :)
Daniele Castagna
2015/06/10 18:02:27
Done.
| |
356 video_frame.get(), context_3d); | |
357 DCHECK(accelerated_last_image_); | |
297 } | 358 } |
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(); | 359 accelerated_last_frame_timestamp_ = video_frame->timestamp(); |
304 } | 360 } |
305 target_frame = &accelerated_last_frame_; | 361 target_frame = &accelerated_last_frame_; |
306 accelerated_frame_deleting_timer_.Reset(); | 362 accelerated_frame_deleting_timer_.Reset(); |
307 } else if (canvas->getGrContext()) { | 363 } else if (canvas->getGrContext()) { |
308 if (accelerated_last_frame_.isNull() || | 364 if (accelerated_last_frame_.isNull() || |
309 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 365 video_frame->timestamp() != accelerated_last_frame_timestamp_) { |
310 // Draw SW Video on HW Canvas. | 366 // Draw SW Video on HW Canvas. |
311 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { | 367 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { |
312 // Reset SkBitmap used in HWVideo-to-HWCanvas path. | 368 // 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) { | 444 video_rotation == VIDEO_ROTATION_270) { |
389 rotated_dest_size = | 445 rotated_dest_size = |
390 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 446 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
391 } | 447 } |
392 canvas->scale( | 448 canvas->scale( |
393 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), | 449 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), |
394 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); | 450 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); |
395 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), | 451 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
396 -SkFloatToScalar(target_frame->height() * 0.5f)); | 452 -SkFloatToScalar(target_frame->height() * 0.5f)); |
397 } | 453 } |
398 canvas->drawBitmap(*target_frame, 0, 0, &paint); | 454 if (accelerated_last_image_) { |
455 canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); | |
456 } else { | |
457 canvas->drawBitmap(*target_frame, 0, 0, &paint); | |
458 } | |
399 if (need_transform) | 459 if (need_transform) |
400 canvas->restore(); | 460 canvas->restore(); |
401 canvas->flush(); | 461 canvas->flush(); |
402 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 462 // SkCanvas::flush() causes the generator to generate SkImage, so delete |
403 // |video_frame| not to be outlived. | 463 // |video_frame| not to be outlived. |
404 if (canvas->getGrContext() && accelerated_generator_) | 464 if (canvas->getGrContext() && accelerated_generator_) |
405 accelerated_generator_->set_frame(nullptr); | 465 accelerated_generator_->set_frame(nullptr); |
406 } | 466 } |
407 | 467 |
408 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 468 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: | 601 case VideoFrame::NV12: |
542 #endif | 602 #endif |
543 case VideoFrame::ARGB: | 603 case VideoFrame::ARGB: |
544 case VideoFrame::XRGB: | 604 case VideoFrame::XRGB: |
545 case VideoFrame::UNKNOWN: | 605 case VideoFrame::UNKNOWN: |
546 NOTREACHED(); | 606 NOTREACHED(); |
547 } | 607 } |
548 } | 608 } |
549 | 609 |
550 // static | 610 // static |
551 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 611 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
552 gpu::gles2::GLES2Interface* gl, | 612 gpu::gles2::GLES2Interface* gl, |
553 VideoFrame* video_frame, | 613 VideoFrame* video_frame, |
554 unsigned int texture, | 614 unsigned int texture, |
555 unsigned int internal_format, | 615 unsigned int internal_format, |
556 unsigned int type, | 616 unsigned int type, |
557 bool premultiply_alpha, | 617 bool premultiply_alpha, |
558 bool flip_y) { | 618 bool flip_y) { |
559 DCHECK(video_frame); | 619 DCHECK(video_frame); |
560 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); | 620 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); |
561 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); | 621 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); |
(...skipping 26 matching lines...) Expand all Loading... | |
588 SyncPointClientImpl client(gl); | 648 SyncPointClientImpl client(gl); |
589 video_frame->UpdateReleaseSyncPoint(&client); | 649 video_frame->UpdateReleaseSyncPoint(&client); |
590 } | 650 } |
591 | 651 |
592 void SkCanvasVideoRenderer::ResetLastFrame() { | 652 void SkCanvasVideoRenderer::ResetLastFrame() { |
593 last_frame_.reset(); | 653 last_frame_.reset(); |
594 last_frame_timestamp_ = media::kNoTimestamp(); | 654 last_frame_timestamp_ = media::kNoTimestamp(); |
595 } | 655 } |
596 | 656 |
597 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { | 657 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { |
658 accelerated_last_image_.reset(); | |
598 accelerated_last_frame_.reset(); | 659 accelerated_last_frame_.reset(); |
599 accelerated_generator_ = nullptr; | 660 accelerated_generator_ = nullptr; |
600 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); | 661 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); |
601 } | 662 } |
602 | 663 |
603 } // namespace media | 664 } // namespace media |
OLD | NEW |