Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / media / filters / skcanvas_video_renderer.cc
blob743efc04f648c8fc4171fb50d2909bd4858fdf70
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/filters/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/SkImageGenerator.h"
16 #include "third_party/skia/include/gpu/GrContext.h"
17 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
18 #include "ui/gfx/skbitmap_operations.h"
20 // Skia internal format depends on a platform. On Android it is ABGR, on others
21 // it is ARGB.
22 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
23 SK_A32_SHIFT == 24
24 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
25 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
26 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
27 SK_A32_SHIFT == 24
28 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
29 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
30 #else
31 #error Unexpected Skia ARGB_8888 layout!
32 #endif
34 namespace media {
36 namespace {
38 // This class keeps two temporary resources; software bitmap, hardware bitmap.
39 // If both bitmap are created and then only software bitmap is updated every
40 // frame, hardware bitmap outlives until the media player dies. So we delete
41 // a temporary resource if it is not used for 3 sec.
42 const int kTemporaryResourceDeletionDelay = 3; // Seconds;
44 bool IsYUV(media::VideoFrame::Format format) {
45 switch (format) {
46 case VideoFrame::YV12:
47 case VideoFrame::YV16:
48 case VideoFrame::I420:
49 case VideoFrame::YV12A:
50 case VideoFrame::YV12J:
51 case VideoFrame::YV12HD:
52 case VideoFrame::YV24:
53 case VideoFrame::NV12:
54 return true;
55 case VideoFrame::UNKNOWN:
56 case VideoFrame::NATIVE_TEXTURE:
57 #if defined(VIDEO_HOLE)
58 case VideoFrame::HOLE:
59 #endif // defined(VIDEO_HOLE)
60 case VideoFrame::ARGB:
61 return false;
63 NOTREACHED() << "Invalid videoframe format provided: " << format;
64 return false;
67 bool IsJPEGColorSpace(media::VideoFrame::Format format) {
68 switch (format) {
69 case VideoFrame::YV12J:
70 return true;
71 case VideoFrame::YV12:
72 case VideoFrame::YV12HD:
73 case VideoFrame::YV16:
74 case VideoFrame::I420:
75 case VideoFrame::YV12A:
76 case VideoFrame::YV24:
77 case VideoFrame::NV12:
78 case VideoFrame::UNKNOWN:
79 case VideoFrame::NATIVE_TEXTURE:
80 #if defined(VIDEO_HOLE)
81 case VideoFrame::HOLE:
82 #endif // defined(VIDEO_HOLE)
83 case VideoFrame::ARGB:
84 return false;
86 NOTREACHED() << "Invalid videoframe format provided: " << format;
87 return false;
90 bool IsYUVOrNative(media::VideoFrame::Format format) {
91 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
94 // Converts a |video_frame| to raw |rgb_pixels|.
95 void ConvertVideoFrameToRGBPixels(
96 const scoped_refptr<media::VideoFrame>& video_frame,
97 void* rgb_pixels,
98 size_t row_bytes) {
99 DCHECK(IsYUVOrNative(video_frame->format()))
100 << video_frame->format();
101 if (IsYUV(video_frame->format())) {
102 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
103 video_frame->stride(media::VideoFrame::kVPlane));
106 size_t y_offset = 0;
107 size_t uv_offset = 0;
108 if (IsYUV(video_frame->format())) {
109 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1;
110 // Use the "left" and "top" of the destination rect to locate the offset
111 // in Y, U and V planes.
112 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) *
113 video_frame->visible_rect().y()) +
114 video_frame->visible_rect().x();
115 // For format YV12, there is one U, V value per 2x2 block.
116 // For format YV16, there is one U, V value per 2x1 block.
117 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) *
118 (video_frame->visible_rect().y() >> y_shift)) +
119 (video_frame->visible_rect().x() >> 1);
122 switch (video_frame->format()) {
123 case VideoFrame::YV12:
124 case VideoFrame::I420:
125 LIBYUV_I420_TO_ARGB(
126 video_frame->data(VideoFrame::kYPlane) + y_offset,
127 video_frame->stride(VideoFrame::kYPlane),
128 video_frame->data(VideoFrame::kUPlane) + uv_offset,
129 video_frame->stride(VideoFrame::kUPlane),
130 video_frame->data(VideoFrame::kVPlane) + uv_offset,
131 video_frame->stride(VideoFrame::kVPlane),
132 static_cast<uint8*>(rgb_pixels),
133 row_bytes,
134 video_frame->visible_rect().width(),
135 video_frame->visible_rect().height());
136 break;
138 case VideoFrame::YV12J:
139 ConvertYUVToRGB32(
140 video_frame->data(VideoFrame::kYPlane) + y_offset,
141 video_frame->data(VideoFrame::kUPlane) + uv_offset,
142 video_frame->data(VideoFrame::kVPlane) + uv_offset,
143 static_cast<uint8*>(rgb_pixels),
144 video_frame->visible_rect().width(),
145 video_frame->visible_rect().height(),
146 video_frame->stride(VideoFrame::kYPlane),
147 video_frame->stride(VideoFrame::kUPlane),
148 row_bytes,
149 YV12J);
150 break;
152 case VideoFrame::YV12HD:
153 ConvertYUVToRGB32(
154 video_frame->data(VideoFrame::kYPlane) + y_offset,
155 video_frame->data(VideoFrame::kUPlane) + uv_offset,
156 video_frame->data(VideoFrame::kVPlane) + uv_offset,
157 static_cast<uint8*>(rgb_pixels),
158 video_frame->visible_rect().width(),
159 video_frame->visible_rect().height(),
160 video_frame->stride(VideoFrame::kYPlane),
161 video_frame->stride(VideoFrame::kUPlane),
162 row_bytes,
163 YV12HD);
164 break;
166 case VideoFrame::YV16:
167 LIBYUV_I422_TO_ARGB(
168 video_frame->data(VideoFrame::kYPlane) + y_offset,
169 video_frame->stride(VideoFrame::kYPlane),
170 video_frame->data(VideoFrame::kUPlane) + uv_offset,
171 video_frame->stride(VideoFrame::kUPlane),
172 video_frame->data(VideoFrame::kVPlane) + uv_offset,
173 video_frame->stride(VideoFrame::kVPlane),
174 static_cast<uint8*>(rgb_pixels),
175 row_bytes,
176 video_frame->visible_rect().width(),
177 video_frame->visible_rect().height());
178 break;
180 case VideoFrame::YV12A:
181 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM
182 // optimized.
183 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel.
184 ConvertYUVAToARGB(
185 video_frame->data(VideoFrame::kYPlane) + y_offset,
186 video_frame->data(VideoFrame::kUPlane) + uv_offset,
187 video_frame->data(VideoFrame::kVPlane) + uv_offset,
188 video_frame->data(VideoFrame::kAPlane),
189 static_cast<uint8*>(rgb_pixels),
190 video_frame->visible_rect().width(),
191 video_frame->visible_rect().height(),
192 video_frame->stride(VideoFrame::kYPlane),
193 video_frame->stride(VideoFrame::kUPlane),
194 video_frame->stride(VideoFrame::kAPlane),
195 row_bytes,
196 YV12);
197 break;
199 case VideoFrame::YV24:
200 libyuv::I444ToARGB(
201 video_frame->data(VideoFrame::kYPlane) + y_offset,
202 video_frame->stride(VideoFrame::kYPlane),
203 video_frame->data(VideoFrame::kUPlane) + uv_offset,
204 video_frame->stride(VideoFrame::kUPlane),
205 video_frame->data(VideoFrame::kVPlane) + uv_offset,
206 video_frame->stride(VideoFrame::kVPlane),
207 static_cast<uint8*>(rgb_pixels),
208 row_bytes,
209 video_frame->visible_rect().width(),
210 video_frame->visible_rect().height());
211 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
212 SK_A32_SHIFT == 24
213 libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels),
214 row_bytes,
215 static_cast<uint8*>(rgb_pixels),
216 row_bytes,
217 video_frame->visible_rect().width(),
218 video_frame->visible_rect().height());
219 #endif
220 break;
222 case VideoFrame::NATIVE_TEXTURE: {
223 SkBitmap tmp;
224 tmp.installPixels(
225 SkImageInfo::MakeN32Premul(video_frame->visible_rect().width(),
226 video_frame->visible_rect().height()),
227 rgb_pixels,
228 row_bytes);
229 video_frame->ReadPixelsFromNativeTexture(tmp);
230 break;
233 #if defined(VIDEO_HOLE)
234 case VideoFrame::HOLE:
235 #endif // defined(VIDEO_HOLE)
236 case VideoFrame::ARGB:
237 case VideoFrame::UNKNOWN:
238 case VideoFrame::NV12:
239 NOTREACHED();
243 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap,
244 const gfx::Size& size) {
245 return bitmap->getTexture() && bitmap->width() == size.width() &&
246 bitmap->height() == size.height();
249 bool AllocateSkBitmapTexture(GrContext* gr,
250 SkBitmap* bitmap,
251 const gfx::Size& size) {
252 DCHECK(gr);
253 GrTextureDesc desc;
254 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid
255 // RGBA to BGRA conversion.
256 desc.fConfig = kRGBA_8888_GrPixelConfig;
257 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
258 desc.fSampleCnt = 0;
259 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
260 desc.fWidth = size.width();
261 desc.fHeight = size.height();
262 skia::RefPtr<GrTexture> texture = skia::AdoptRef(
263 gr->refScratchTexture(desc, GrContext::kExact_ScratchTexMatch));
264 if (!texture.get())
265 return false;
267 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
268 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
269 if (!pixel_ref)
270 return false;
271 bitmap->setInfo(info);
272 bitmap->setPixelRef(pixel_ref)->unref();
273 return true;
276 bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame,
277 SkBitmap* bitmap,
278 const Context3D& context_3d) {
279 // Check if we could reuse existing texture based bitmap.
280 // Otherwise, release existing texture based bitmap and allocate
281 // a new one based on video size.
282 if (!IsSkBitmapProperlySizedTexture(bitmap,
283 video_frame->visible_rect().size())) {
284 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap,
285 video_frame->visible_rect().size())) {
286 return false;
290 unsigned texture_id =
291 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
292 // If CopyVideoFrameTextureToGLTexture() changes the state of the
293 // |texture_id|, it's needed to invalidate the state cached in skia,
294 // but currently the state isn't changed.
295 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
296 context_3d.gl, video_frame, texture_id, 0, GL_RGBA, GL_UNSIGNED_BYTE,
297 true, false);
298 return true;
301 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
302 public:
303 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
304 ~SyncPointClientImpl() override {}
305 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
306 void WaitSyncPoint(uint32 sync_point) override {
307 gl_->WaitSyncPointCHROMIUM(sync_point);
310 private:
311 gpu::gles2::GLES2Interface* gl_;
313 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
316 } // anonymous namespace
318 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
319 class VideoImageGenerator : public SkImageGenerator {
320 public:
321 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {
322 DCHECK(frame_.get());
324 ~VideoImageGenerator() override {}
326 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; }
328 protected:
329 bool onGetInfo(SkImageInfo* info) override {
330 info->fWidth = frame_->visible_rect().width();
331 info->fHeight = frame_->visible_rect().height();
332 info->fColorType = kN32_SkColorType;
333 info->fAlphaType = kPremul_SkAlphaType;
334 return true;
337 bool onGetPixels(const SkImageInfo& info,
338 void* pixels,
339 size_t row_bytes,
340 SkPMColor ctable[],
341 int* ctable_count) override {
342 if (!frame_.get())
343 return false;
344 if (!pixels)
345 return false;
346 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
347 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes);
348 return true;
351 bool onGetYUV8Planes(SkISize sizes[3],
352 void* planes[3],
353 size_t row_bytes[3],
354 SkYUVColorSpace* color_space) override {
355 if (!frame_.get() || !IsYUV(frame_->format()) ||
356 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion,
357 // Remove this case once it does. As-is we will fall back on the
358 // pure-software path in this case.
359 frame_->format() == VideoFrame::YV12HD) {
360 return false;
363 if (color_space) {
364 if (IsJPEGColorSpace(frame_->format()))
365 *color_space = kJPEG_SkYUVColorSpace;
366 else
367 *color_space = kRec601_SkYUVColorSpace;
370 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
371 ++plane) {
372 if (sizes) {
373 gfx::Size size;
374 size =
375 VideoFrame::PlaneSize(frame_->format(),
376 plane,
377 gfx::Size(frame_->visible_rect().width(),
378 frame_->visible_rect().height()));
379 sizes[plane].set(size.width(), size.height());
381 if (row_bytes && planes) {
382 size_t offset;
383 int y_shift = (frame_->format() == media::VideoFrame::YV16) ? 0 : 1;
384 if (plane == media::VideoFrame::kYPlane) {
385 offset = (frame_->stride(media::VideoFrame::kYPlane) *
386 frame_->visible_rect().y()) +
387 frame_->visible_rect().x();
388 } else {
389 offset = (frame_->stride(media::VideoFrame::kUPlane) *
390 (frame_->visible_rect().y() >> y_shift)) +
391 (frame_->visible_rect().x() >> 1);
393 row_bytes[plane] = static_cast<size_t>(frame_->stride(plane));
394 planes[plane] = frame_->data(plane) + offset;
397 return true;
400 private:
401 scoped_refptr<VideoFrame> frame_;
403 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
406 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
407 : last_frame_timestamp_(media::kNoTimestamp()),
408 frame_deleting_timer_(
409 FROM_HERE,
410 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
411 this,
412 &SkCanvasVideoRenderer::ResetLastFrame),
413 accelerated_generator_(nullptr),
414 accelerated_last_frame_timestamp_(media::kNoTimestamp()),
415 accelerated_frame_deleting_timer_(
416 FROM_HERE,
417 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
418 this,
419 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame) {
420 last_frame_.setIsVolatile(true);
423 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
425 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
426 SkCanvas* canvas,
427 const gfx::RectF& dest_rect,
428 uint8 alpha,
429 SkXfermode::Mode mode,
430 VideoRotation video_rotation,
431 const Context3D& context_3d) {
432 if (alpha == 0) {
433 return;
436 SkRect dest;
437 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
439 SkPaint paint;
440 paint.setAlpha(alpha);
442 // Paint black rectangle if there isn't a frame available or the
443 // frame has an unexpected format.
444 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
445 !IsYUVOrNative(video_frame->format())) {
446 canvas->drawRect(dest, paint);
447 canvas->flush();
448 return;
451 SkBitmap* target_frame = nullptr;
452 if (canvas->getGrContext()) {
453 if (accelerated_last_frame_.isNull() ||
454 video_frame->timestamp() != accelerated_last_frame_timestamp_) {
455 if (video_frame->format() == VideoFrame::NATIVE_TEXTURE) {
456 // Draw HW Video on HW Canvas.
457 DCHECK(context_3d.gl);
458 DCHECK(context_3d.gr_context);
459 if (accelerated_generator_) {
460 // Reset SkBitmap used in SWVideo-to-HWCanvas path.
461 accelerated_last_frame_.reset();
462 accelerated_generator_ = nullptr;
464 if (!CopyVideoFrameTextureToSkBitmapTexture(
465 video_frame.get(), &accelerated_last_frame_, context_3d)) {
466 NOTREACHED();
467 return;
469 } else {
470 // Draw SW Video on HW Canvas.
471 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) {
472 // Reset SkBitmap used in HWVideo-to-HWCanvas path.
473 accelerated_last_frame_.reset();
475 accelerated_generator_ = new VideoImageGenerator(video_frame);
477 // Note: This takes ownership of |accelerated_generator_|.
478 if (!SkInstallDiscardablePixelRef(accelerated_generator_,
479 &accelerated_last_frame_)) {
480 NOTREACHED();
481 return;
484 DCHECK(video_frame->visible_rect().width() ==
485 accelerated_last_frame_.width() &&
486 video_frame->visible_rect().height() ==
487 accelerated_last_frame_.height());
489 accelerated_last_frame_timestamp_ = video_frame->timestamp();
490 } else if (accelerated_generator_) {
491 accelerated_generator_->set_frame(video_frame);
493 target_frame = &accelerated_last_frame_;
494 accelerated_frame_deleting_timer_.Reset();
495 } else {
496 // Draw both SW and HW Video on SW Canvas.
497 if (last_frame_.isNull() ||
498 video_frame->timestamp() != last_frame_timestamp_) {
499 // Check if |bitmap| needs to be (re)allocated.
500 if (last_frame_.isNull() ||
501 last_frame_.width() != video_frame->visible_rect().width() ||
502 last_frame_.height() != video_frame->visible_rect().height()) {
503 last_frame_.allocN32Pixels(video_frame->visible_rect().width(),
504 video_frame->visible_rect().height());
505 last_frame_.setIsVolatile(true);
507 last_frame_.lockPixels();
508 ConvertVideoFrameToRGBPixels(
509 video_frame, last_frame_.getPixels(), last_frame_.rowBytes());
510 last_frame_.notifyPixelsChanged();
511 last_frame_.unlockPixels();
512 last_frame_timestamp_ = video_frame->timestamp();
514 target_frame = &last_frame_;
515 frame_deleting_timer_.Reset();
518 paint.setXfermodeMode(mode);
519 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
521 bool need_transform =
522 video_rotation != VIDEO_ROTATION_0 ||
523 dest_rect.size() != video_frame->visible_rect().size() ||
524 !dest_rect.origin().IsOrigin();
525 if (need_transform) {
526 canvas->save();
527 canvas->translate(
528 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)),
529 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f)));
530 SkScalar angle = SkFloatToScalar(0.0f);
531 switch (video_rotation) {
532 case VIDEO_ROTATION_0:
533 break;
534 case VIDEO_ROTATION_90:
535 angle = SkFloatToScalar(90.0f);
536 break;
537 case VIDEO_ROTATION_180:
538 angle = SkFloatToScalar(180.0f);
539 break;
540 case VIDEO_ROTATION_270:
541 angle = SkFloatToScalar(270.0f);
542 break;
544 canvas->rotate(angle);
546 gfx::SizeF rotated_dest_size = dest_rect.size();
547 if (video_rotation == VIDEO_ROTATION_90 ||
548 video_rotation == VIDEO_ROTATION_270) {
549 rotated_dest_size =
550 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
552 canvas->scale(
553 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()),
554 SkFloatToScalar(rotated_dest_size.height() / target_frame->height()));
555 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f),
556 -SkFloatToScalar(target_frame->height() * 0.5f));
558 canvas->drawBitmap(*target_frame, 0, 0, &paint);
559 if (need_transform)
560 canvas->restore();
561 canvas->flush();
562 // SkCanvas::flush() causes the generator to generate SkImage, so delete
563 // |video_frame| not to be outlived.
564 if (canvas->getGrContext() && accelerated_generator_)
565 accelerated_generator_->set_frame(nullptr);
568 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
569 SkCanvas* canvas) {
570 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff,
571 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, Context3D());
574 // static
575 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
576 gpu::gles2::GLES2Interface* gl,
577 VideoFrame* video_frame,
578 unsigned int texture,
579 unsigned int level,
580 unsigned int internal_format,
581 unsigned int type,
582 bool premultiply_alpha,
583 bool flip_y) {
584 DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE);
585 const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
586 DCHECK(mailbox_holder->texture_target == GL_TEXTURE_2D ||
587 mailbox_holder->texture_target == GL_TEXTURE_RECTANGLE_ARB ||
588 mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES);
590 gl->WaitSyncPointCHROMIUM(mailbox_holder->sync_point);
591 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
592 mailbox_holder->texture_target, mailbox_holder->mailbox.name);
594 // The video is stored in a unmultiplied format, so premultiply
595 // if necessary.
596 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha);
597 // Application itself needs to take care of setting the right |flip_y|
598 // value down to get the expected result.
599 // "flip_y == true" means to reverse the video orientation while
600 // "flip_y == false" means to keep the intrinsic orientation.
601 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
602 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture, level,
603 internal_format, type);
604 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
605 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
607 gl->DeleteTextures(1, &source_texture);
608 gl->Flush();
610 SyncPointClientImpl client(gl);
611 video_frame->UpdateReleaseSyncPoint(&client);
614 void SkCanvasVideoRenderer::ResetLastFrame() {
615 last_frame_.reset();
616 last_frame_timestamp_ = media::kNoTimestamp();
619 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() {
620 accelerated_last_frame_.reset();
621 accelerated_generator_ = nullptr;
622 accelerated_last_frame_timestamp_ = media::kNoTimestamp();
625 } // namespace media