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 "third_party/skia/include/gpu/SkGrPixelRef.h"
23 #include "ui/gfx/skbitmap_operations.h"
25 // Skia internal format depends on a platform. On Android it is ABGR, on others
27 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
31 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
33 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
34 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
36 #error Unexpected Skia ARGB_8888 layout!
43 // This class keeps two temporary resources; software bitmap, hardware bitmap.
44 // If both bitmap are created and then only software bitmap is updated every
45 // frame, hardware bitmap outlives until the media player dies. So we delete
46 // a temporary resource if it is not used for 3 sec.
47 const int kTemporaryResourceDeletionDelay
= 3; // Seconds;
49 bool CheckColorSpace(const scoped_refptr
<VideoFrame
>& video_frame
,
50 ColorSpace color_space
) {
52 return video_frame
->metadata()->GetInteger(
53 VideoFrameMetadata::COLOR_SPACE
, &result
) &&
54 result
== color_space
;
57 bool IsSkBitmapProperlySizedTexture(const SkBitmap
* bitmap
,
58 const gfx::Size
& size
) {
59 return bitmap
->getTexture() && bitmap
->width() == size
.width() &&
60 bitmap
->height() == size
.height();
63 bool AllocateSkBitmapTexture(GrContext
* gr
,
65 const gfx::Size
& size
) {
68 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid
69 // RGBA to BGRA conversion.
70 desc
.fConfig
= kRGBA_8888_GrPixelConfig
;
71 desc
.fFlags
= kRenderTarget_GrSurfaceFlag
;
73 desc
.fOrigin
= kTopLeft_GrSurfaceOrigin
;
74 desc
.fWidth
= size
.width();
75 desc
.fHeight
= size
.height();
76 skia::RefPtr
<GrTexture
> texture
= skia::AdoptRef(
77 gr
->textureProvider()->refScratchTexture(
78 desc
, GrTextureProvider::kExact_ScratchTexMatch
));
82 SkImageInfo info
= SkImageInfo::MakeN32Premul(desc
.fWidth
, desc
.fHeight
);
83 SkGrPixelRef
* pixel_ref
= SkNEW_ARGS(SkGrPixelRef
, (info
, texture
.get()));
86 bitmap
->setInfo(info
);
87 bitmap
->setPixelRef(pixel_ref
)->unref();
91 class SyncPointClientImpl
: public VideoFrame::SyncPointClient
{
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
);
101 gpu::gles2::GLES2Interface
* gl_
;
103 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl
);
106 scoped_ptr
<SkImage
> CreateSkImageFromVideoFrameYUVTextures(
107 VideoFrame
* video_frame
,
108 const Context3D
& context_3d
) {
109 // Support only TEXTURE_YUV_420.
110 DCHECK(video_frame
->HasTextures());
111 DCHECK_EQ(media::PIXEL_FORMAT_I420
, video_frame
->format());
112 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame
->format()));
114 gpu::gles2::GLES2Interface
* gl
= context_3d
.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);
120 unsigned source_textures
[3] = {0};
121 for (size_t i
= 0; i
< media::VideoFrame::NumPlanes(video_frame
->format());
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
);
132 // TODO(dcastagna): avoid this copy once Skia supports native textures
133 // with a texture target different than TEXTURE_2D.
135 if (mailbox_holder
.texture_target
!= GL_TEXTURE_2D
) {
136 unsigned texture_copy
= 0;
137 gl
->GenTextures(1, &texture_copy
);
138 DCHECK(texture_copy
);
139 gl
->BindTexture(GL_TEXTURE_2D
, texture_copy
);
140 gl
->CopyTextureCHROMIUM(GL_TEXTURE_2D
, source_textures
[i
], texture_copy
,
141 GL_RGB
, GL_UNSIGNED_BYTE
, false, true, false);
143 gl
->DeleteTextures(1, &source_textures
[i
]);
144 source_textures
[i
] = texture_copy
;
147 GrBackendObject handles
[3] = {
148 source_textures
[0], source_textures
[1], source_textures
[2]};
150 SkISize yuvSizes
[] = {
151 {ya_tex_size
.width(), ya_tex_size
.height()},
152 {uv_tex_size
.width(), uv_tex_size
.height()},
153 {uv_tex_size
.width(), uv_tex_size
.height()},
156 // TODO(dcastagna): Skia currently doesn't support Rec709 YUV conversion.
157 DCHECK(!CheckColorSpace(video_frame
, media::COLOR_SPACE_HD_REC709
));
158 SkYUVColorSpace color_space
= kRec601_SkYUVColorSpace
;
159 if (CheckColorSpace(video_frame
, media::COLOR_SPACE_JPEG
))
160 color_space
= kJPEG_SkYUVColorSpace
;
162 SkImage
* img
= SkImage::NewFromYUVTexturesCopy(context_3d
.gr_context
,
163 color_space
, handles
, yuvSizes
,
164 kTopLeft_GrSurfaceOrigin
);
166 gl
->DeleteTextures(3, source_textures
);
167 SyncPointClientImpl
client(gl
);
168 video_frame
->UpdateReleaseSyncPoint(&client
);
169 return make_scoped_ptr(img
);
172 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame
* video_frame
,
174 const Context3D
& context_3d
) {
175 // Check if we could reuse existing texture based bitmap.
176 // Otherwise, release existing texture based bitmap and allocate
177 // a new one based on video size.
178 if (!IsSkBitmapProperlySizedTexture(bitmap
,
179 video_frame
->visible_rect().size())) {
180 if (!AllocateSkBitmapTexture(context_3d
.gr_context
, bitmap
,
181 video_frame
->visible_rect().size())) {
186 unsigned texture_id
=
187 static_cast<unsigned>((bitmap
->getTexture())->getTextureHandle());
188 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the
189 // |texture_id|, it's needed to invalidate the state cached in skia,
190 // but currently the state isn't changed.
192 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
193 context_3d
.gl
, video_frame
, texture_id
, GL_RGBA
, GL_UNSIGNED_BYTE
, true,
195 bitmap
->notifyPixelsChanged();
199 } // anonymous namespace
201 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
202 class VideoImageGenerator
: public SkImageGenerator
{
204 VideoImageGenerator(const scoped_refptr
<VideoFrame
>& frame
)
206 SkImageInfo::MakeN32Premul(frame
->visible_rect().width(),
207 frame
->visible_rect().height()))
209 DCHECK(frame_
.get());
211 ~VideoImageGenerator() override
{}
213 void set_frame(const scoped_refptr
<VideoFrame
>& frame
) { frame_
= frame
; }
216 Result
onGetPixels(const SkImageInfo
& info
,
221 int* ctable_count
) override
{
223 return kInvalidInput
;
224 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
225 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
226 frame_
, pixels
, row_bytes
);
230 bool onGetYUV8Planes(SkISize sizes
[3],
233 SkYUVColorSpace
* color_space
) override
{
234 if (!frame_
.get() || !media::IsYuvPlanar(frame_
->format()) ||
235 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion,
236 // or YUVA conversion. Remove this case once it does. As-is we will
237 // fall back on the pure-software path in this case.
238 CheckColorSpace(frame_
, COLOR_SPACE_HD_REC709
) ||
239 frame_
->format() == PIXEL_FORMAT_YV12A
) {
244 if (CheckColorSpace(frame_
, COLOR_SPACE_JPEG
))
245 *color_space
= kJPEG_SkYUVColorSpace
;
247 *color_space
= kRec601_SkYUVColorSpace
;
250 for (int plane
= VideoFrame::kYPlane
; plane
<= VideoFrame::kVPlane
;
253 const gfx::Size size
=
254 VideoFrame::PlaneSize(frame_
->format(), plane
,
255 gfx::Size(frame_
->visible_rect().width(),
256 frame_
->visible_rect().height()));
257 sizes
[plane
].set(size
.width(), size
.height());
259 if (row_bytes
&& planes
) {
262 (frame_
->format() == media::PIXEL_FORMAT_YV16
) ? 0 : 1;
263 if (plane
== VideoFrame::kYPlane
) {
264 offset
= (frame_
->stride(VideoFrame::kYPlane
) *
265 frame_
->visible_rect().y()) +
266 frame_
->visible_rect().x();
268 offset
= (frame_
->stride(VideoFrame::kUPlane
) *
269 (frame_
->visible_rect().y() >> y_shift
)) +
270 (frame_
->visible_rect().x() >> 1);
273 // Copy the frame to the supplied memory.
274 // TODO: Find a way (API change?) to avoid this copy.
275 char* out_line
= static_cast<char*>(planes
[plane
]);
276 int out_line_stride
= row_bytes
[plane
];
277 uint8
* in_line
= frame_
->data(plane
) + offset
;
278 int in_line_stride
= frame_
->stride(plane
);
279 int plane_height
= sizes
[plane
].height();
280 if (in_line_stride
== out_line_stride
) {
281 memcpy(out_line
, in_line
, plane_height
* in_line_stride
);
283 // Different line padding so need to copy one line at a time.
284 int bytes_to_copy_per_line
= out_line_stride
< in_line_stride
287 for (int line_no
= 0; line_no
< plane_height
; line_no
++) {
288 memcpy(out_line
, in_line
, bytes_to_copy_per_line
);
289 in_line
+= in_line_stride
;
290 out_line
+= out_line_stride
;
299 scoped_refptr
<VideoFrame
> frame_
;
301 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator
);
304 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
305 : last_frame_timestamp_(media::kNoTimestamp()),
306 frame_deleting_timer_(
308 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay
),
310 &SkCanvasVideoRenderer::ResetLastFrame
),
311 accelerated_generator_(nullptr),
312 accelerated_last_frame_timestamp_(media::kNoTimestamp()),
313 accelerated_frame_deleting_timer_(
315 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay
),
317 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame
) {
318 last_frame_
.setIsVolatile(true);
321 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
323 void SkCanvasVideoRenderer::Paint(const scoped_refptr
<VideoFrame
>& video_frame
,
325 const gfx::RectF
& dest_rect
,
327 SkXfermode::Mode mode
,
328 VideoRotation video_rotation
,
329 const Context3D
& context_3d
) {
335 dest
.set(dest_rect
.x(), dest_rect
.y(), dest_rect
.right(), dest_rect
.bottom());
338 paint
.setAlpha(alpha
);
340 // Paint black rectangle if there isn't a frame available or the
341 // frame has an unexpected format.
342 if (!video_frame
.get() || video_frame
->natural_size().IsEmpty() ||
343 !(media::IsYuvPlanar(video_frame
->format()) ||
344 video_frame
->HasTextures())) {
345 canvas
->drawRect(dest
, paint
);
350 SkBitmap
* target_frame
= nullptr;
352 if (video_frame
->HasTextures()) {
353 // Draw HW Video on both SW and HW Canvas.
354 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas.
355 if (accelerated_last_frame_
.isNull() ||
356 video_frame
->timestamp() != accelerated_last_frame_timestamp_
) {
357 DCHECK(context_3d
.gl
);
358 DCHECK(context_3d
.gr_context
);
359 if (accelerated_generator_
) {
360 // Reset SkBitmap used in SWVideo-to-HWCanvas path.
361 accelerated_last_frame_
.reset();
362 accelerated_generator_
= nullptr;
365 if (media::VideoFrame::NumPlanes(video_frame
->format()) == 1) {
366 accelerated_last_image_
.reset();
367 if (!CopyVideoFrameSingleTextureToSkBitmap(
368 video_frame
.get(), &accelerated_last_frame_
, context_3d
)) {
372 DCHECK(video_frame
->visible_rect().width() ==
373 accelerated_last_frame_
.width() &&
374 video_frame
->visible_rect().height() ==
375 accelerated_last_frame_
.height());
377 accelerated_last_image_
= CreateSkImageFromVideoFrameYUVTextures(
378 video_frame
.get(), context_3d
);
379 DCHECK(accelerated_last_image_
);
381 accelerated_last_frame_timestamp_
= video_frame
->timestamp();
383 target_frame
= &accelerated_last_frame_
;
384 accelerated_frame_deleting_timer_
.Reset();
385 } else if (canvas
->getGrContext()) {
386 if (accelerated_last_frame_
.isNull() ||
387 video_frame
->timestamp() != accelerated_last_frame_timestamp_
) {
388 // Draw SW Video on HW Canvas.
389 if (!accelerated_generator_
&& !accelerated_last_frame_
.isNull()) {
390 // Reset SkBitmap used in HWVideo-to-HWCanvas path.
391 accelerated_last_frame_
.reset();
393 accelerated_generator_
= new VideoImageGenerator(video_frame
);
395 // Note: This takes ownership of |accelerated_generator_|.
396 if (!SkInstallDiscardablePixelRef(accelerated_generator_
,
397 &accelerated_last_frame_
)) {
401 DCHECK(video_frame
->visible_rect().width() ==
402 accelerated_last_frame_
.width() &&
403 video_frame
->visible_rect().height() ==
404 accelerated_last_frame_
.height());
406 accelerated_last_frame_timestamp_
= video_frame
->timestamp();
407 } else if (accelerated_generator_
) {
408 accelerated_generator_
->set_frame(video_frame
);
410 target_frame
= &accelerated_last_frame_
;
411 accelerated_frame_deleting_timer_
.Reset();
413 // Draw SW Video on SW Canvas.
414 DCHECK(video_frame
->IsMappable());
415 if (last_frame_
.isNull() ||
416 video_frame
->timestamp() != last_frame_timestamp_
) {
417 // Check if |bitmap| needs to be (re)allocated.
418 if (last_frame_
.isNull() ||
419 last_frame_
.width() != video_frame
->visible_rect().width() ||
420 last_frame_
.height() != video_frame
->visible_rect().height()) {
421 last_frame_
.allocN32Pixels(video_frame
->visible_rect().width(),
422 video_frame
->visible_rect().height());
423 last_frame_
.setIsVolatile(true);
425 last_frame_
.lockPixels();
426 ConvertVideoFrameToRGBPixels(
427 video_frame
, last_frame_
.getPixels(), last_frame_
.rowBytes());
428 last_frame_
.notifyPixelsChanged();
429 last_frame_
.unlockPixels();
430 last_frame_timestamp_
= video_frame
->timestamp();
432 target_frame
= &last_frame_
;
433 frame_deleting_timer_
.Reset();
436 paint
.setXfermodeMode(mode
);
437 paint
.setFilterQuality(kLow_SkFilterQuality
);
439 const bool need_transform
=
440 video_rotation
!= VIDEO_ROTATION_0
||
441 dest_rect
.size() != video_frame
->visible_rect().size() ||
442 !dest_rect
.origin().IsOrigin();
443 if (need_transform
) {
446 SkFloatToScalar(dest_rect
.x() + (dest_rect
.width() * 0.5f
)),
447 SkFloatToScalar(dest_rect
.y() + (dest_rect
.height() * 0.5f
)));
448 SkScalar angle
= SkFloatToScalar(0.0f
);
449 switch (video_rotation
) {
450 case VIDEO_ROTATION_0
:
452 case VIDEO_ROTATION_90
:
453 angle
= SkFloatToScalar(90.0f
);
455 case VIDEO_ROTATION_180
:
456 angle
= SkFloatToScalar(180.0f
);
458 case VIDEO_ROTATION_270
:
459 angle
= SkFloatToScalar(270.0f
);
462 canvas
->rotate(angle
);
464 gfx::SizeF rotated_dest_size
= dest_rect
.size();
465 if (video_rotation
== VIDEO_ROTATION_90
||
466 video_rotation
== VIDEO_ROTATION_270
) {
468 gfx::SizeF(rotated_dest_size
.height(), rotated_dest_size
.width());
471 SkFloatToScalar(rotated_dest_size
.width() / target_frame
->width()),
472 SkFloatToScalar(rotated_dest_size
.height() / target_frame
->height()));
473 canvas
->translate(-SkFloatToScalar(target_frame
->width() * 0.5f
),
474 -SkFloatToScalar(target_frame
->height() * 0.5f
));
476 if (accelerated_last_image_
) {
477 canvas
->drawImage(accelerated_last_image_
.get(), 0, 0, &paint
);
479 canvas
->drawBitmap(*target_frame
, 0, 0, &paint
);
484 // SkCanvas::flush() causes the generator to generate SkImage, so delete
485 // |video_frame| not to be outlived.
486 if (canvas
->getGrContext() && accelerated_generator_
)
487 accelerated_generator_
->set_frame(nullptr);
490 void SkCanvasVideoRenderer::Copy(const scoped_refptr
<VideoFrame
>& video_frame
,
492 const Context3D
& context_3d
) {
493 Paint(video_frame
, canvas
, video_frame
->visible_rect(), 0xff,
494 SkXfermode::kSrc_Mode
, media::VIDEO_ROTATION_0
, context_3d
);
498 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
499 const scoped_refptr
<VideoFrame
>& video_frame
,
502 if (!video_frame
->IsMappable()) {
503 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats.";
506 if (!media::IsYuvPlanar(video_frame
->format())) {
507 NOTREACHED() << "Non YUV formats are not supported";
511 DCHECK_EQ(video_frame
->stride(VideoFrame::kUPlane
),
512 video_frame
->stride(VideoFrame::kVPlane
));
515 (video_frame
->format() == media::PIXEL_FORMAT_YV16
) ? 0 : 1;
516 // Use the "left" and "top" of the destination rect to locate the offset
517 // in Y, U and V planes.
518 const size_t y_offset
= (video_frame
->stride(VideoFrame::kYPlane
) *
519 video_frame
->visible_rect().y()) +
520 video_frame
->visible_rect().x();
521 // For format YV12, there is one U, V value per 2x2 block.
522 // For format YV16, there is one U, V value per 2x1 block.
523 const size_t uv_offset
= (video_frame
->stride(VideoFrame::kUPlane
) *
524 (video_frame
->visible_rect().y() >> y_shift
)) +
525 (video_frame
->visible_rect().x() >> 1);
527 switch (video_frame
->format()) {
528 case PIXEL_FORMAT_YV12
:
529 case PIXEL_FORMAT_I420
:
530 if (CheckColorSpace(video_frame
, COLOR_SPACE_JPEG
)) {
532 video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
533 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
534 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
535 static_cast<uint8
*>(rgb_pixels
),
536 video_frame
->visible_rect().width(),
537 video_frame
->visible_rect().height(),
538 video_frame
->stride(VideoFrame::kYPlane
),
539 video_frame
->stride(VideoFrame::kUPlane
),
542 } else if (CheckColorSpace(video_frame
, COLOR_SPACE_HD_REC709
)) {
543 ConvertYUVToRGB32(video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
544 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
545 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
546 static_cast<uint8
*>(rgb_pixels
),
547 video_frame
->visible_rect().width(),
548 video_frame
->visible_rect().height(),
549 video_frame
->stride(VideoFrame::kYPlane
),
550 video_frame
->stride(VideoFrame::kUPlane
), row_bytes
,
554 video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
555 video_frame
->stride(VideoFrame::kYPlane
),
556 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
557 video_frame
->stride(VideoFrame::kUPlane
),
558 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
559 video_frame
->stride(VideoFrame::kVPlane
),
560 static_cast<uint8
*>(rgb_pixels
),
562 video_frame
->visible_rect().width(),
563 video_frame
->visible_rect().height());
566 case PIXEL_FORMAT_YV16
:
568 video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
569 video_frame
->stride(VideoFrame::kYPlane
),
570 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
571 video_frame
->stride(VideoFrame::kUPlane
),
572 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
573 video_frame
->stride(VideoFrame::kVPlane
),
574 static_cast<uint8
*>(rgb_pixels
),
576 video_frame
->visible_rect().width(),
577 video_frame
->visible_rect().height());
580 case PIXEL_FORMAT_YV12A
:
581 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM
583 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel.
585 video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
586 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
587 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
588 video_frame
->data(VideoFrame::kAPlane
),
589 static_cast<uint8
*>(rgb_pixels
),
590 video_frame
->visible_rect().width(),
591 video_frame
->visible_rect().height(),
592 video_frame
->stride(VideoFrame::kYPlane
),
593 video_frame
->stride(VideoFrame::kUPlane
),
594 video_frame
->stride(VideoFrame::kAPlane
),
599 case PIXEL_FORMAT_YV24
:
601 video_frame
->data(VideoFrame::kYPlane
) + y_offset
,
602 video_frame
->stride(VideoFrame::kYPlane
),
603 video_frame
->data(VideoFrame::kUPlane
) + uv_offset
,
604 video_frame
->stride(VideoFrame::kUPlane
),
605 video_frame
->data(VideoFrame::kVPlane
) + uv_offset
,
606 video_frame
->stride(VideoFrame::kVPlane
),
607 static_cast<uint8
*>(rgb_pixels
),
609 video_frame
->visible_rect().width(),
610 video_frame
->visible_rect().height());
611 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
613 libyuv::ARGBToABGR(static_cast<uint8
*>(rgb_pixels
),
615 static_cast<uint8
*>(rgb_pixels
),
617 video_frame
->visible_rect().width(),
618 video_frame
->visible_rect().height());
621 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
622 case PIXEL_FORMAT_NV12
:
624 case PIXEL_FORMAT_ARGB
:
625 case PIXEL_FORMAT_XRGB
:
626 case PIXEL_FORMAT_UNKNOWN
:
632 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
633 gpu::gles2::GLES2Interface
* gl
,
634 VideoFrame
* video_frame
,
635 unsigned int texture
,
636 unsigned int internal_format
,
638 bool premultiply_alpha
,
641 DCHECK(video_frame
->HasTextures());
642 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame
->format()));
644 const gpu::MailboxHolder
& mailbox_holder
= video_frame
->mailbox_holder(0);
645 DCHECK(mailbox_holder
.texture_target
== GL_TEXTURE_2D
||
646 mailbox_holder
.texture_target
== GL_TEXTURE_RECTANGLE_ARB
||
647 mailbox_holder
.texture_target
== GL_TEXTURE_EXTERNAL_OES
);
649 gl
->WaitSyncPointCHROMIUM(mailbox_holder
.sync_point
);
650 uint32 source_texture
= gl
->CreateAndConsumeTextureCHROMIUM(
651 mailbox_holder
.texture_target
, mailbox_holder
.mailbox
.name
);
653 // The video is stored in a unmultiplied format, so premultiply
655 // Application itself needs to take care of setting the right |flip_y|
656 // value down to get the expected result.
657 // "flip_y == true" means to reverse the video orientation while
658 // "flip_y == false" means to keep the intrinsic orientation.
659 gl
->CopyTextureCHROMIUM(GL_TEXTURE_2D
, source_texture
, texture
,
660 internal_format
, type
,
661 flip_y
, premultiply_alpha
, false);
663 gl
->DeleteTextures(1, &source_texture
);
666 SyncPointClientImpl
client(gl
);
667 video_frame
->UpdateReleaseSyncPoint(&client
);
670 void SkCanvasVideoRenderer::ResetLastFrame() {
672 last_frame_timestamp_
= media::kNoTimestamp();
675 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() {
676 accelerated_last_image_
.reset();
677 accelerated_last_frame_
.reset();
678 accelerated_generator_
= nullptr;
679 accelerated_last_frame_timestamp_
= media::kNoTimestamp();