Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / blink / skcanvas_video_renderer.cc
blob4115d9a47919c584523bb4634adb2f919ca477f4
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"
21 #include "third_party/skia/include/gpu/SkGr.h"
22 #include "ui/gfx/geometry/rect_f.h"
24 // Skia internal format depends on a platform. On Android it is ABGR, on others
25 // it is ARGB.
26 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
27 SK_A32_SHIFT == 24
28 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
29 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
30 #define LIBYUV_I420ALPHA_TO_ARGB libyuv::I420AlphaToARGB
31 #define LIBYUV_J420_TO_ARGB libyuv::J420ToARGB
32 #define LIBYUV_H420_TO_ARGB libyuv::H420ToARGB
33 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
34 SK_A32_SHIFT == 24
35 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
36 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
37 #define LIBYUV_I420ALPHA_TO_ARGB libyuv::I420AlphaToABGR
38 #define LIBYUV_J420_TO_ARGB libyuv::J420ToABGR
39 #define LIBYUV_H420_TO_ARGB libyuv::H420ToABGR
40 #else
41 #error Unexpected Skia ARGB_8888 layout!
42 #endif
44 namespace media {
46 namespace {
48 // This class keeps the last image drawn.
49 // We delete the temporary resource if it is not used for 3 seconds.
50 const int kTemporaryResourceDeletionDelay = 3; // Seconds;
52 bool CheckColorSpace(const VideoFrame* video_frame, ColorSpace color_space) {
53 int result;
54 return video_frame->metadata()->GetInteger(
55 VideoFrameMetadata::COLOR_SPACE, &result) &&
56 result == color_space;
59 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
60 public:
61 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
62 ~SyncPointClientImpl() override {}
63 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
64 void WaitSyncPoint(uint32 sync_point) override {
65 gl_->WaitSyncPointCHROMIUM(sync_point);
68 private:
69 gpu::gles2::GLES2Interface* gl_;
71 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
74 skia::RefPtr<SkImage> NewSkImageFromVideoFrameYUVTextures(
75 const VideoFrame* video_frame,
76 const Context3D& context_3d) {
77 // Support only TEXTURE_YUV_420.
78 DCHECK(video_frame->HasTextures());
79 DCHECK_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
80 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format()));
82 gpu::gles2::GLES2Interface* gl = context_3d.gl;
83 DCHECK(gl);
84 gfx::Size ya_tex_size = video_frame->coded_size();
85 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
86 (ya_tex_size.height() + 1) / 2);
88 unsigned source_textures[3] = {0};
89 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format());
90 ++i) {
91 // Get the texture from the mailbox and wrap it in a GrTexture.
92 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
93 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
94 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES ||
95 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB);
96 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
97 source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM(
98 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
100 // TODO(dcastagna): avoid this copy once Skia supports native textures
101 // with a texture target different than TEXTURE_2D.
102 // crbug.com/505026
103 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
104 unsigned texture_copy = 0;
105 gl->GenTextures(1, &texture_copy);
106 DCHECK(texture_copy);
107 gl->BindTexture(GL_TEXTURE_2D, texture_copy);
108 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_textures[i], texture_copy,
109 GL_RGB, GL_UNSIGNED_BYTE, false, true, false);
111 gl->DeleteTextures(1, &source_textures[i]);
112 source_textures[i] = texture_copy;
115 GrBackendObject handles[3] = {
116 source_textures[0], source_textures[1], source_textures[2]};
118 SkISize yuvSizes[] = {
119 {ya_tex_size.width(), ya_tex_size.height()},
120 {uv_tex_size.width(), uv_tex_size.height()},
121 {uv_tex_size.width(), uv_tex_size.height()},
124 SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
125 if (CheckColorSpace(video_frame, media::COLOR_SPACE_JPEG))
126 color_space = kJPEG_SkYUVColorSpace;
127 else if (CheckColorSpace(video_frame, media::COLOR_SPACE_HD_REC709))
128 color_space = kRec709_SkYUVColorSpace;
130 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context,
131 color_space, handles, yuvSizes,
132 kTopLeft_GrSurfaceOrigin);
133 gl->DeleteTextures(3, source_textures);
134 return skia::AdoptRef(img);
137 // Creates a SkImage from a |video_frame| backed by native resources.
138 // The SkImage will take ownership of the underlying resource.
139 skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
140 VideoFrame* video_frame,
141 const Context3D& context_3d) {
142 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
143 PIXEL_FORMAT_NV12 == video_frame->format() ||
144 PIXEL_FORMAT_UYVY == video_frame->format());
146 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
147 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
148 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
149 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
150 << mailbox_holder.texture_target;
152 gpu::gles2::GLES2Interface* gl = context_3d.gl;
153 unsigned source_texture = 0;
154 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
155 // TODO(dcastagna): At the moment Skia doesn't support targets different
156 // than GL_TEXTURE_2D. Avoid this copy once
157 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
158 gl->GenTextures(1, &source_texture);
159 DCHECK(source_texture);
160 gl->BindTexture(GL_TEXTURE_2D, source_texture);
161 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
162 gl, video_frame, source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true,
163 false);
164 } else {
165 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
166 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
167 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
169 GrBackendTextureDesc desc;
170 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
171 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
172 desc.fWidth = video_frame->coded_size().width();
173 desc.fHeight = video_frame->coded_size().height();
174 desc.fConfig = kRGBA_8888_GrPixelConfig;
175 desc.fTextureHandle = source_texture;
176 return skia::AdoptRef(
177 SkImage::NewFromAdoptedTexture(context_3d.gr_context, desc));
180 } // anonymous namespace
182 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
183 class VideoImageGenerator : public SkImageGenerator {
184 public:
185 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame)
186 : SkImageGenerator(
187 SkImageInfo::MakeN32Premul(frame->visible_rect().width(),
188 frame->visible_rect().height())),
189 frame_(frame) {
190 DCHECK(!frame_->HasTextures());
192 ~VideoImageGenerator() override {}
194 protected:
195 bool onGetPixels(const SkImageInfo& info,
196 void* pixels,
197 size_t row_bytes,
198 SkPMColor ctable[],
199 int* ctable_count) override {
200 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
201 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(frame_.get(), pixels,
202 row_bytes);
203 return true;
206 bool onGetYUV8Planes(SkISize sizes[3],
207 void* planes[3],
208 size_t row_bytes[3],
209 SkYUVColorSpace* color_space) override {
210 if (!media::IsYuvPlanar(frame_->format()) ||
211 // TODO(rileya): Skia currently doesn't support YUVA conversion. Remove
212 // this case once it does. As-is we will fall back on the pure-software
213 // path in this case.
214 frame_->format() == PIXEL_FORMAT_YV12A) {
215 return false;
218 if (color_space) {
219 if (CheckColorSpace(frame_.get(), COLOR_SPACE_JPEG))
220 *color_space = kJPEG_SkYUVColorSpace;
221 else if (CheckColorSpace(frame_.get(), COLOR_SPACE_HD_REC709))
222 *color_space = kRec709_SkYUVColorSpace;
223 else
224 *color_space = kRec601_SkYUVColorSpace;
227 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
228 ++plane) {
229 if (sizes) {
230 const gfx::Size size =
231 VideoFrame::PlaneSize(frame_->format(), plane,
232 gfx::Size(frame_->visible_rect().width(),
233 frame_->visible_rect().height()));
234 sizes[plane].set(size.width(), size.height());
236 if (row_bytes && planes) {
237 size_t offset;
238 const int y_shift =
239 (frame_->format() == media::PIXEL_FORMAT_YV16) ? 0 : 1;
240 if (plane == VideoFrame::kYPlane) {
241 offset = (frame_->stride(VideoFrame::kYPlane) *
242 frame_->visible_rect().y()) +
243 frame_->visible_rect().x();
244 } else {
245 offset = (frame_->stride(VideoFrame::kUPlane) *
246 (frame_->visible_rect().y() >> y_shift)) +
247 (frame_->visible_rect().x() >> 1);
250 // Copy the frame to the supplied memory.
251 // TODO: Find a way (API change?) to avoid this copy.
252 char* out_line = static_cast<char*>(planes[plane]);
253 int out_line_stride = row_bytes[plane];
254 uint8* in_line = frame_->data(plane) + offset;
255 int in_line_stride = frame_->stride(plane);
256 int plane_height = sizes[plane].height();
257 if (in_line_stride == out_line_stride) {
258 memcpy(out_line, in_line, plane_height * in_line_stride);
259 } else {
260 // Different line padding so need to copy one line at a time.
261 int bytes_to_copy_per_line = out_line_stride < in_line_stride
262 ? out_line_stride
263 : in_line_stride;
264 for (int line_no = 0; line_no < plane_height; line_no++) {
265 memcpy(out_line, in_line, bytes_to_copy_per_line);
266 in_line += in_line_stride;
267 out_line += out_line_stride;
272 return true;
275 private:
276 scoped_refptr<VideoFrame> frame_;
278 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
281 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
282 : last_image_deleting_timer_(
283 FROM_HERE,
284 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
285 this,
286 &SkCanvasVideoRenderer::ResetCache) {}
288 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {
289 ResetCache();
292 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
293 SkCanvas* canvas,
294 const gfx::RectF& dest_rect,
295 uint8 alpha,
296 SkXfermode::Mode mode,
297 VideoRotation video_rotation,
298 const Context3D& context_3d) {
299 if (alpha == 0) {
300 return;
303 SkRect dest;
304 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
306 SkPaint paint;
307 paint.setAlpha(alpha);
309 // Paint black rectangle if there isn't a frame available or the
310 // frame has an unexpected format.
311 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
312 !(media::IsYuvPlanar(video_frame->format()) ||
313 video_frame->HasTextures())) {
314 canvas->drawRect(dest, paint);
315 canvas->flush();
316 return;
319 gpu::gles2::GLES2Interface* gl = context_3d.gl;
321 if (!last_image_ || video_frame->timestamp() != last_timestamp_) {
322 ResetCache();
323 // Generate a new image.
324 // Note: Skia will hold onto |video_frame| via |video_generator| only when
325 // |video_frame| is software.
326 // Holding |video_frame| longer than this call when using GPUVideoDecoder
327 // could cause problems since the pool of VideoFrames has a fixed size.
328 if (video_frame->HasTextures()) {
329 DCHECK(context_3d.gr_context);
330 DCHECK(gl);
331 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) {
332 last_image_ =
333 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d);
334 } else {
335 last_image_ =
336 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d);
338 } else {
339 auto video_generator = new VideoImageGenerator(video_frame);
340 last_image_ = skia::AdoptRef(SkImage::NewFromGenerator(video_generator));
342 if (!last_image_) // Couldn't create the SkImage.
343 return;
344 last_timestamp_ = video_frame->timestamp();
346 last_image_deleting_timer_.Reset();
348 paint.setXfermodeMode(mode);
349 paint.setFilterQuality(kLow_SkFilterQuality);
351 const bool need_transform =
352 video_rotation != VIDEO_ROTATION_0 ||
353 dest_rect.size() != video_frame->visible_rect().size() ||
354 !dest_rect.origin().IsOrigin();
355 if (need_transform) {
356 canvas->save();
357 canvas->translate(
358 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)),
359 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f)));
360 SkScalar angle = SkFloatToScalar(0.0f);
361 switch (video_rotation) {
362 case VIDEO_ROTATION_0:
363 break;
364 case VIDEO_ROTATION_90:
365 angle = SkFloatToScalar(90.0f);
366 break;
367 case VIDEO_ROTATION_180:
368 angle = SkFloatToScalar(180.0f);
369 break;
370 case VIDEO_ROTATION_270:
371 angle = SkFloatToScalar(270.0f);
372 break;
374 canvas->rotate(angle);
376 gfx::SizeF rotated_dest_size = dest_rect.size();
377 if (video_rotation == VIDEO_ROTATION_90 ||
378 video_rotation == VIDEO_ROTATION_270) {
379 rotated_dest_size =
380 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
382 canvas->scale(
383 SkFloatToScalar(rotated_dest_size.width() / last_image_->width()),
384 SkFloatToScalar(rotated_dest_size.height() / last_image_->height()));
385 canvas->translate(-SkFloatToScalar(last_image_->width() * 0.5f),
386 -SkFloatToScalar(last_image_->height() * 0.5f));
389 // This is a workaround for crbug.com/524717. SkBitmaps are read back before a
390 // SkPicture is sent to multiple threads while SkImages are not. The long term
391 // solution is for Skia to provide a SkPicture filter that makes a picture
392 // safe for multiple CPU raster threads (skbug.com/4321). We limit the
393 // workaround to cases where the src frame is a texture and the canvas is
394 // recording.
395 if (last_image_.get()->getTexture() &&
396 canvas->imageInfo().colorType() == kUnknown_SkColorType) {
397 SkBitmap bmp;
398 GrWrapTextureInBitmap(last_image_.get()->getTexture(),
399 last_image_.get()->width(), last_image_.get()->height(), true, &bmp);
400 // Even though the bitmap is logically immutable we do not mark it as such
401 // because doing so would defer readback until rasterization, which will be
402 // on another thread and is therefore unsafe.
403 canvas->drawBitmap(bmp, 0, 0, &paint);
404 } else {
405 canvas->drawImage(last_image_.get(), 0, 0, &paint);
408 if (need_transform)
409 canvas->restore();
410 // Make sure to flush so we can remove the videoframe from the generator.
411 canvas->flush();
413 if (video_frame->HasTextures()) {
414 DCHECK(gl);
415 SyncPointClientImpl client(gl);
416 video_frame->UpdateReleaseSyncPoint(&client);
420 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
421 SkCanvas* canvas,
422 const Context3D& context_3d) {
423 Paint(video_frame, canvas, gfx::RectF(video_frame->visible_rect()), 0xff,
424 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d);
427 // static
428 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
429 const VideoFrame* video_frame,
430 void* rgb_pixels,
431 size_t row_bytes) {
432 if (!video_frame->IsMappable()) {
433 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats.";
434 return;
436 if (!media::IsYuvPlanar(video_frame->format())) {
437 NOTREACHED() << "Non YUV formats are not supported";
438 return;
440 DCHECK_EQ(video_frame->stride(VideoFrame::kUPlane),
441 video_frame->stride(VideoFrame::kVPlane));
443 switch (video_frame->format()) {
444 case PIXEL_FORMAT_YV12:
445 case PIXEL_FORMAT_I420:
446 if (CheckColorSpace(video_frame, COLOR_SPACE_JPEG)) {
447 LIBYUV_J420_TO_ARGB(
448 video_frame->visible_data(VideoFrame::kYPlane),
449 video_frame->stride(VideoFrame::kYPlane),
450 video_frame->visible_data(VideoFrame::kUPlane),
451 video_frame->stride(VideoFrame::kUPlane),
452 video_frame->visible_data(VideoFrame::kVPlane),
453 video_frame->stride(VideoFrame::kVPlane),
454 static_cast<uint8*>(rgb_pixels),
455 row_bytes,
456 video_frame->visible_rect().width(),
457 video_frame->visible_rect().height());
458 } else if (CheckColorSpace(video_frame, COLOR_SPACE_HD_REC709)) {
459 LIBYUV_H420_TO_ARGB(
460 video_frame->visible_data(VideoFrame::kYPlane),
461 video_frame->stride(VideoFrame::kYPlane),
462 video_frame->visible_data(VideoFrame::kUPlane),
463 video_frame->stride(VideoFrame::kUPlane),
464 video_frame->visible_data(VideoFrame::kVPlane),
465 video_frame->stride(VideoFrame::kVPlane),
466 static_cast<uint8*>(rgb_pixels),
467 row_bytes,
468 video_frame->visible_rect().width(),
469 video_frame->visible_rect().height());
470 } else {
471 LIBYUV_I420_TO_ARGB(
472 video_frame->visible_data(VideoFrame::kYPlane),
473 video_frame->stride(VideoFrame::kYPlane),
474 video_frame->visible_data(VideoFrame::kUPlane),
475 video_frame->stride(VideoFrame::kUPlane),
476 video_frame->visible_data(VideoFrame::kVPlane),
477 video_frame->stride(VideoFrame::kVPlane),
478 static_cast<uint8*>(rgb_pixels),
479 row_bytes,
480 video_frame->visible_rect().width(),
481 video_frame->visible_rect().height());
483 break;
484 case PIXEL_FORMAT_YV16:
485 LIBYUV_I422_TO_ARGB(
486 video_frame->visible_data(VideoFrame::kYPlane),
487 video_frame->stride(VideoFrame::kYPlane),
488 video_frame->visible_data(VideoFrame::kUPlane),
489 video_frame->stride(VideoFrame::kUPlane),
490 video_frame->visible_data(VideoFrame::kVPlane),
491 video_frame->stride(VideoFrame::kVPlane),
492 static_cast<uint8*>(rgb_pixels),
493 row_bytes,
494 video_frame->visible_rect().width(),
495 video_frame->visible_rect().height());
496 break;
498 case PIXEL_FORMAT_YV12A:
499 LIBYUV_I420ALPHA_TO_ARGB(
500 video_frame->visible_data(VideoFrame::kYPlane),
501 video_frame->stride(VideoFrame::kYPlane),
502 video_frame->visible_data(VideoFrame::kUPlane),
503 video_frame->stride(VideoFrame::kUPlane),
504 video_frame->visible_data(VideoFrame::kVPlane),
505 video_frame->stride(VideoFrame::kVPlane),
506 video_frame->visible_data(VideoFrame::kAPlane),
507 video_frame->stride(VideoFrame::kAPlane),
508 static_cast<uint8*>(rgb_pixels),
509 row_bytes,
510 video_frame->visible_rect().width(),
511 video_frame->visible_rect().height());
512 break;
514 case PIXEL_FORMAT_YV24:
515 libyuv::I444ToARGB(
516 video_frame->visible_data(VideoFrame::kYPlane),
517 video_frame->stride(VideoFrame::kYPlane),
518 video_frame->visible_data(VideoFrame::kUPlane),
519 video_frame->stride(VideoFrame::kUPlane),
520 video_frame->visible_data(VideoFrame::kVPlane),
521 video_frame->stride(VideoFrame::kVPlane),
522 static_cast<uint8*>(rgb_pixels),
523 row_bytes,
524 video_frame->visible_rect().width(),
525 video_frame->visible_rect().height());
526 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
527 SK_A32_SHIFT == 24
528 libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels),
529 row_bytes,
530 static_cast<uint8*>(rgb_pixels),
531 row_bytes,
532 video_frame->visible_rect().width(),
533 video_frame->visible_rect().height());
534 #endif
535 break;
536 case PIXEL_FORMAT_NV12:
537 case PIXEL_FORMAT_NV21:
538 case PIXEL_FORMAT_UYVY:
539 case PIXEL_FORMAT_YUY2:
540 case PIXEL_FORMAT_ARGB:
541 case PIXEL_FORMAT_XRGB:
542 case PIXEL_FORMAT_RGB24:
543 case PIXEL_FORMAT_RGB32:
544 case PIXEL_FORMAT_MJPEG:
545 case PIXEL_FORMAT_MT21:
546 case PIXEL_FORMAT_UNKNOWN:
547 NOTREACHED();
551 // static
552 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
553 gpu::gles2::GLES2Interface* gl,
554 VideoFrame* video_frame,
555 unsigned int texture,
556 unsigned int internal_format,
557 unsigned int type,
558 bool premultiply_alpha,
559 bool flip_y) {
560 DCHECK(video_frame);
561 DCHECK(video_frame->HasTextures());
562 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format()));
564 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
565 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
566 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
567 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
568 << mailbox_holder.texture_target;
570 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
571 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
572 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
574 // The video is stored in a unmultiplied format, so premultiply
575 // if necessary.
576 // Application itself needs to take care of setting the right |flip_y|
577 // value down to get the expected result.
578 // "flip_y == true" means to reverse the video orientation while
579 // "flip_y == false" means to keep the intrinsic orientation.
580 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture,
581 internal_format, type,
582 flip_y, premultiply_alpha, false);
584 gl->DeleteTextures(1, &source_texture);
585 gl->Flush();
587 SyncPointClientImpl client(gl);
588 video_frame->UpdateReleaseSyncPoint(&client);
591 void SkCanvasVideoRenderer::ResetCache() {
592 // Clear cached values.
593 last_image_ = nullptr;
594 last_timestamp_ = kNoTimestamp();
597 } // namespace media