Revert of [Android] Add a java.lang.System wrapper. (patchset #2 id:20001 of https...
[chromium-blink-merge.git] / media / blink / skcanvas_video_renderer.cc
blobdb711dc8f55c96ab06bd17b9a5358017600dbc7c
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
3 // found in the LICENSE file.
5 #include "media/blink/skcanvas_video_renderer.h"
7 #include "gpu/GLES2/gl2extchromium.h"
8 #include "gpu/command_buffer/client/gles2_interface.h"
9 #include "gpu/command_buffer/common/mailbox_holder.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/yuv_convert.h"
12 #include "skia/ext/refptr.h"
13 #include "third_party/libyuv/include/libyuv.h"
14 #include "third_party/skia/include/core/SkCanvas.h"
15 #include "third_party/skia/include/core/SkImage.h"
16 #include "third_party/skia/include/core/SkImageGenerator.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"
20 #include "third_party/skia/include/gpu/GrTextureProvider.h"
22 // Skia internal format depends on a platform. On Android it is ABGR, on others
23 // it is ARGB.
24 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
25 SK_A32_SHIFT == 24
26 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
27 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
28 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
29 SK_A32_SHIFT == 24
30 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
31 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
32 #else
33 #error Unexpected Skia ARGB_8888 layout!
34 #endif
36 namespace media {
38 namespace {
40 // This class keeps the last image drawn.
41 // We delete the temporary resource if it is not used for 3 seconds.
42 const int kTemporaryResourceDeletionDelay = 3; // Seconds;
44 bool CheckColorSpace(const VideoFrame* video_frame, ColorSpace color_space) {
45 int result;
46 return video_frame->metadata()->GetInteger(
47 VideoFrameMetadata::COLOR_SPACE, &result) &&
48 result == color_space;
51 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
52 public:
53 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
54 ~SyncPointClientImpl() override {}
55 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
56 void WaitSyncPoint(uint32 sync_point) override {
57 gl_->WaitSyncPointCHROMIUM(sync_point);
60 private:
61 gpu::gles2::GLES2Interface* gl_;
63 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
66 skia::RefPtr<SkImage> NewSkImageFromVideoFrameYUVTextures(
67 const VideoFrame* video_frame,
68 const Context3D& context_3d) {
69 // Support only TEXTURE_YUV_420.
70 DCHECK(video_frame->HasTextures());
71 DCHECK_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
72 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format()));
74 gpu::gles2::GLES2Interface* gl = context_3d.gl;
75 DCHECK(gl);
76 gfx::Size ya_tex_size = video_frame->coded_size();
77 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
78 (ya_tex_size.height() + 1) / 2);
80 unsigned source_textures[3] = {0};
81 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format());
82 ++i) {
83 // Get the texture from the mailbox and wrap it in a GrTexture.
84 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
85 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
86 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES ||
87 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB);
88 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
89 source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM(
90 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
92 // TODO(dcastagna): avoid this copy once Skia supports native textures
93 // with a texture target different than TEXTURE_2D.
94 // crbug.com/505026
95 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
96 unsigned texture_copy = 0;
97 gl->GenTextures(1, &texture_copy);
98 DCHECK(texture_copy);
99 gl->BindTexture(GL_TEXTURE_2D, texture_copy);
100 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_textures[i], texture_copy,
101 GL_RGB, GL_UNSIGNED_BYTE, false, true, false);
103 gl->DeleteTextures(1, &source_textures[i]);
104 source_textures[i] = texture_copy;
107 GrBackendObject handles[3] = {
108 source_textures[0], source_textures[1], source_textures[2]};
110 SkISize yuvSizes[] = {
111 {ya_tex_size.width(), ya_tex_size.height()},
112 {uv_tex_size.width(), uv_tex_size.height()},
113 {uv_tex_size.width(), uv_tex_size.height()},
116 SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
117 if (CheckColorSpace(video_frame, media::COLOR_SPACE_JPEG))
118 color_space = kJPEG_SkYUVColorSpace;
119 else if (CheckColorSpace(video_frame, media::COLOR_SPACE_HD_REC709))
120 color_space = kRec709_SkYUVColorSpace;
122 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context,
123 color_space, handles, yuvSizes,
124 kTopLeft_GrSurfaceOrigin);
125 DCHECK(img);
126 gl->DeleteTextures(3, source_textures);
127 return skia::AdoptRef(img);
130 bool ShouldCacheVideoFrameSkImage(const VideoFrame* video_frame) {
131 return !video_frame->HasTextures() ||
132 media::VideoFrame::NumPlanes(video_frame->format()) != 1 ||
133 video_frame->mailbox_holder(0).texture_target != GL_TEXTURE_2D;
136 // Creates a SkImage from a |video_frame| backed by native resources.
137 // The SkImage will take ownership of the underlying resource.
138 skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
139 VideoFrame* video_frame,
140 const Context3D& context_3d) {
141 DCHECK_EQ(PIXEL_FORMAT_ARGB, video_frame->format());
143 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
144 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
145 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
146 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
147 << mailbox_holder.texture_target;
149 gpu::gles2::GLES2Interface* gl = context_3d.gl;
150 unsigned source_texture = 0;
151 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
152 // TODO(dcastagna): At the moment Skia doesn't support targets different
153 // than GL_TEXTURE_2D. Avoid this copy once
154 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
155 gl->GenTextures(1, &source_texture);
156 DCHECK(source_texture);
157 gl->BindTexture(GL_TEXTURE_2D, source_texture);
158 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
159 gl, video_frame, source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true,
160 false);
161 } else {
162 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
163 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
164 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
166 GrBackendTextureDesc desc;
167 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
168 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
169 desc.fWidth = video_frame->coded_size().width();
170 desc.fHeight = video_frame->coded_size().height();
171 desc.fConfig = kRGBA_8888_GrPixelConfig;
172 desc.fTextureHandle = source_texture;
173 return skia::AdoptRef(
174 SkImage::NewFromAdoptedTexture(context_3d.gr_context, desc));
177 } // anonymous namespace
179 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
180 class VideoImageGenerator : public SkImageGenerator {
181 public:
182 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame)
183 : SkImageGenerator(
184 SkImageInfo::MakeN32Premul(frame->visible_rect().width(),
185 frame->visible_rect().height())),
186 frame_(frame) {
187 DCHECK(!frame_->HasTextures());
189 ~VideoImageGenerator() override {}
191 protected:
192 bool onGetPixels(const SkImageInfo& info,
193 void* pixels,
194 size_t row_bytes,
195 SkPMColor ctable[],
196 int* ctable_count) override {
197 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
198 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(frame_.get(), pixels,
199 row_bytes);
200 return true;
203 bool onGetYUV8Planes(SkISize sizes[3],
204 void* planes[3],
205 size_t row_bytes[3],
206 SkYUVColorSpace* color_space) override {
207 if (!media::IsYuvPlanar(frame_->format()) ||
208 // TODO(rileya): Skia currently doesn't support YUVA conversion. Remove
209 // this case once it does. As-is we will fall back on the pure-software
210 // path in this case.
211 frame_->format() == PIXEL_FORMAT_YV12A) {
212 return false;
215 if (color_space) {
216 if (CheckColorSpace(frame_.get(), COLOR_SPACE_JPEG))
217 *color_space = kJPEG_SkYUVColorSpace;
218 else if (CheckColorSpace(frame_.get(), COLOR_SPACE_HD_REC709))
219 *color_space = kRec709_SkYUVColorSpace;
220 else
221 *color_space = kRec601_SkYUVColorSpace;
224 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
225 ++plane) {
226 if (sizes) {
227 const gfx::Size size =
228 VideoFrame::PlaneSize(frame_->format(), plane,
229 gfx::Size(frame_->visible_rect().width(),
230 frame_->visible_rect().height()));
231 sizes[plane].set(size.width(), size.height());
233 if (row_bytes && planes) {
234 size_t offset;
235 const int y_shift =
236 (frame_->format() == media::PIXEL_FORMAT_YV16) ? 0 : 1;
237 if (plane == VideoFrame::kYPlane) {
238 offset = (frame_->stride(VideoFrame::kYPlane) *
239 frame_->visible_rect().y()) +
240 frame_->visible_rect().x();
241 } else {
242 offset = (frame_->stride(VideoFrame::kUPlane) *
243 (frame_->visible_rect().y() >> y_shift)) +
244 (frame_->visible_rect().x() >> 1);
247 // Copy the frame to the supplied memory.
248 // TODO: Find a way (API change?) to avoid this copy.
249 char* out_line = static_cast<char*>(planes[plane]);
250 int out_line_stride = row_bytes[plane];
251 uint8* in_line = frame_->data(plane) + offset;
252 int in_line_stride = frame_->stride(plane);
253 int plane_height = sizes[plane].height();
254 if (in_line_stride == out_line_stride) {
255 memcpy(out_line, in_line, plane_height * in_line_stride);
256 } else {
257 // Different line padding so need to copy one line at a time.
258 int bytes_to_copy_per_line = out_line_stride < in_line_stride
259 ? out_line_stride
260 : in_line_stride;
261 for (int line_no = 0; line_no < plane_height; line_no++) {
262 memcpy(out_line, in_line, bytes_to_copy_per_line);
263 in_line += in_line_stride;
264 out_line += out_line_stride;
269 return true;
272 private:
273 scoped_refptr<VideoFrame> frame_;
275 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
278 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
279 : last_image_deleting_timer_(
280 FROM_HERE,
281 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
282 this,
283 &SkCanvasVideoRenderer::ResetCache) {}
285 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {
286 ResetCache();
289 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
290 SkCanvas* canvas,
291 const gfx::RectF& dest_rect,
292 uint8 alpha,
293 SkXfermode::Mode mode,
294 VideoRotation video_rotation,
295 const Context3D& context_3d) {
296 if (alpha == 0) {
297 return;
300 SkRect dest;
301 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
303 SkPaint paint;
304 paint.setAlpha(alpha);
306 // Paint black rectangle if there isn't a frame available or the
307 // frame has an unexpected format.
308 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
309 !(media::IsYuvPlanar(video_frame->format()) ||
310 video_frame->HasTextures())) {
311 canvas->drawRect(dest, paint);
312 canvas->flush();
313 return;
316 gpu::gles2::GLES2Interface* gl = context_3d.gl;
318 if (!last_image_ || video_frame->timestamp() != last_timestamp_) {
319 ResetCache();
320 // Generate a new image.
321 // Note: Skia will hold onto |video_frame| via |video_generator| only when
322 // |video_frame| is software.
323 // Holding |video_frame| longer than this call when using GPUVideoDecoder
324 // could cause problems since the pool of VideoFrames has a fixed size.
325 if (video_frame->HasTextures()) {
326 DCHECK(context_3d.gr_context);
327 DCHECK(gl);
328 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) {
329 last_image_ =
330 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d);
331 } else {
332 last_image_ =
333 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d);
335 } else {
336 auto video_generator = new VideoImageGenerator(video_frame);
337 last_image_ = skia::AdoptRef(SkImage::NewFromGenerator(video_generator));
339 last_timestamp_ = video_frame->timestamp();
341 last_image_deleting_timer_.Reset();
343 paint.setXfermodeMode(mode);
344 paint.setFilterQuality(kLow_SkFilterQuality);
346 const bool need_transform =
347 video_rotation != VIDEO_ROTATION_0 ||
348 dest_rect.size() != video_frame->visible_rect().size() ||
349 !dest_rect.origin().IsOrigin();
350 if (need_transform) {
351 canvas->save();
352 canvas->translate(
353 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)),
354 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f)));
355 SkScalar angle = SkFloatToScalar(0.0f);
356 switch (video_rotation) {
357 case VIDEO_ROTATION_0:
358 break;
359 case VIDEO_ROTATION_90:
360 angle = SkFloatToScalar(90.0f);
361 break;
362 case VIDEO_ROTATION_180:
363 angle = SkFloatToScalar(180.0f);
364 break;
365 case VIDEO_ROTATION_270:
366 angle = SkFloatToScalar(270.0f);
367 break;
369 canvas->rotate(angle);
371 gfx::SizeF rotated_dest_size = dest_rect.size();
372 if (video_rotation == VIDEO_ROTATION_90 ||
373 video_rotation == VIDEO_ROTATION_270) {
374 rotated_dest_size =
375 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
377 canvas->scale(
378 SkFloatToScalar(rotated_dest_size.width() / last_image_->width()),
379 SkFloatToScalar(rotated_dest_size.height() / last_image_->height()));
380 canvas->translate(-SkFloatToScalar(last_image_->width() * 0.5f),
381 -SkFloatToScalar(last_image_->height() * 0.5f));
383 canvas->drawImage(last_image_.get(), 0, 0, &paint);
385 if (need_transform)
386 canvas->restore();
387 // Make sure to flush so we can remove the videoframe from the generator.
388 canvas->flush();
390 if (!ShouldCacheVideoFrameSkImage(video_frame.get()))
391 ResetCache();
393 if (video_frame->HasTextures()) {
394 DCHECK(gl);
395 SyncPointClientImpl client(gl);
396 video_frame->UpdateReleaseSyncPoint(&client);
400 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
401 SkCanvas* canvas,
402 const Context3D& context_3d) {
403 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff,
404 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d);
407 // static
408 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
409 const VideoFrame* video_frame,
410 void* rgb_pixels,
411 size_t row_bytes) {
412 if (!video_frame->IsMappable()) {
413 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats.";
414 return;
416 if (!media::IsYuvPlanar(video_frame->format())) {
417 NOTREACHED() << "Non YUV formats are not supported";
418 return;
421 DCHECK_EQ(video_frame->stride(VideoFrame::kUPlane),
422 video_frame->stride(VideoFrame::kVPlane));
424 const int y_shift =
425 (video_frame->format() == media::PIXEL_FORMAT_YV16) ? 0 : 1;
426 // Use the "left" and "top" of the destination rect to locate the offset
427 // in Y, U and V planes.
428 const size_t y_offset = (video_frame->stride(VideoFrame::kYPlane) *
429 video_frame->visible_rect().y()) +
430 video_frame->visible_rect().x();
431 // For format YV12, there is one U, V value per 2x2 block.
432 // For format YV16, there is one U, V value per 2x1 block.
433 const size_t uv_offset = (video_frame->stride(VideoFrame::kUPlane) *
434 (video_frame->visible_rect().y() >> y_shift)) +
435 (video_frame->visible_rect().x() >> 1);
437 switch (video_frame->format()) {
438 case PIXEL_FORMAT_YV12:
439 case PIXEL_FORMAT_I420:
440 if (CheckColorSpace(video_frame, COLOR_SPACE_JPEG)) {
441 ConvertYUVToRGB32(
442 video_frame->data(VideoFrame::kYPlane) + y_offset,
443 video_frame->data(VideoFrame::kUPlane) + uv_offset,
444 video_frame->data(VideoFrame::kVPlane) + uv_offset,
445 static_cast<uint8*>(rgb_pixels),
446 video_frame->visible_rect().width(),
447 video_frame->visible_rect().height(),
448 video_frame->stride(VideoFrame::kYPlane),
449 video_frame->stride(VideoFrame::kUPlane),
450 row_bytes,
451 YV12J);
452 } else if (CheckColorSpace(video_frame, COLOR_SPACE_HD_REC709)) {
453 ConvertYUVToRGB32(video_frame->data(VideoFrame::kYPlane) + y_offset,
454 video_frame->data(VideoFrame::kUPlane) + uv_offset,
455 video_frame->data(VideoFrame::kVPlane) + uv_offset,
456 static_cast<uint8*>(rgb_pixels),
457 video_frame->visible_rect().width(),
458 video_frame->visible_rect().height(),
459 video_frame->stride(VideoFrame::kYPlane),
460 video_frame->stride(VideoFrame::kUPlane), row_bytes,
461 YV12HD);
462 } else {
463 LIBYUV_I420_TO_ARGB(
464 video_frame->data(VideoFrame::kYPlane) + y_offset,
465 video_frame->stride(VideoFrame::kYPlane),
466 video_frame->data(VideoFrame::kUPlane) + uv_offset,
467 video_frame->stride(VideoFrame::kUPlane),
468 video_frame->data(VideoFrame::kVPlane) + uv_offset,
469 video_frame->stride(VideoFrame::kVPlane),
470 static_cast<uint8*>(rgb_pixels),
471 row_bytes,
472 video_frame->visible_rect().width(),
473 video_frame->visible_rect().height());
475 break;
476 case PIXEL_FORMAT_YV16:
477 LIBYUV_I422_TO_ARGB(
478 video_frame->data(VideoFrame::kYPlane) + y_offset,
479 video_frame->stride(VideoFrame::kYPlane),
480 video_frame->data(VideoFrame::kUPlane) + uv_offset,
481 video_frame->stride(VideoFrame::kUPlane),
482 video_frame->data(VideoFrame::kVPlane) + uv_offset,
483 video_frame->stride(VideoFrame::kVPlane),
484 static_cast<uint8*>(rgb_pixels),
485 row_bytes,
486 video_frame->visible_rect().width(),
487 video_frame->visible_rect().height());
488 break;
490 case PIXEL_FORMAT_YV12A:
491 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM
492 // optimized.
493 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel.
494 ConvertYUVAToARGB(
495 video_frame->data(VideoFrame::kYPlane) + y_offset,
496 video_frame->data(VideoFrame::kUPlane) + uv_offset,
497 video_frame->data(VideoFrame::kVPlane) + uv_offset,
498 video_frame->data(VideoFrame::kAPlane),
499 static_cast<uint8*>(rgb_pixels),
500 video_frame->visible_rect().width(),
501 video_frame->visible_rect().height(),
502 video_frame->stride(VideoFrame::kYPlane),
503 video_frame->stride(VideoFrame::kUPlane),
504 video_frame->stride(VideoFrame::kAPlane),
505 row_bytes,
506 YV12);
507 break;
509 case PIXEL_FORMAT_YV24:
510 libyuv::I444ToARGB(
511 video_frame->data(VideoFrame::kYPlane) + y_offset,
512 video_frame->stride(VideoFrame::kYPlane),
513 video_frame->data(VideoFrame::kUPlane) + uv_offset,
514 video_frame->stride(VideoFrame::kUPlane),
515 video_frame->data(VideoFrame::kVPlane) + uv_offset,
516 video_frame->stride(VideoFrame::kVPlane),
517 static_cast<uint8*>(rgb_pixels),
518 row_bytes,
519 video_frame->visible_rect().width(),
520 video_frame->visible_rect().height());
521 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
522 SK_A32_SHIFT == 24
523 libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels),
524 row_bytes,
525 static_cast<uint8*>(rgb_pixels),
526 row_bytes,
527 video_frame->visible_rect().width(),
528 video_frame->visible_rect().height());
529 #endif
530 break;
531 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
532 case PIXEL_FORMAT_NV12:
533 #endif
534 case PIXEL_FORMAT_ARGB:
535 case PIXEL_FORMAT_XRGB:
536 case PIXEL_FORMAT_UNKNOWN:
537 NOTREACHED();
541 // static
542 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
543 gpu::gles2::GLES2Interface* gl,
544 VideoFrame* video_frame,
545 unsigned int texture,
546 unsigned int internal_format,
547 unsigned int type,
548 bool premultiply_alpha,
549 bool flip_y) {
550 DCHECK(video_frame);
551 DCHECK(video_frame->HasTextures());
552 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format()));
554 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
555 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
556 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
557 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
558 << mailbox_holder.texture_target;
560 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
561 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
562 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
564 // The video is stored in a unmultiplied format, so premultiply
565 // if necessary.
566 // Application itself needs to take care of setting the right |flip_y|
567 // value down to get the expected result.
568 // "flip_y == true" means to reverse the video orientation while
569 // "flip_y == false" means to keep the intrinsic orientation.
570 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture,
571 internal_format, type,
572 flip_y, premultiply_alpha, false);
574 gl->DeleteTextures(1, &source_texture);
575 gl->Flush();
577 SyncPointClientImpl client(gl);
578 video_frame->UpdateReleaseSyncPoint(&client);
581 void SkCanvasVideoRenderer::ResetCache() {
582 // Clear cached values.
583 last_image_ = nullptr;
584 last_timestamp_ = kNoTimestamp();
587 } // namespace media