Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(532)

Side by Side Diff: media/blink/skcanvas_video_renderer.cc

Issue 1153623002: media: SkCanvasVideoRenderer support for YUV native videoframes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Set the color format. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/blink/skcanvas_video_renderer.h ('k') | media/blink/webmediaplayer_impl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/blink/skcanvas_video_renderer.h ('k') | media/blink/webmediaplayer_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698