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

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

Issue 445013002: media: Optimize HW Video to 2D Canvas copy. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to ToT. Address nits Created 6 years, 2 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
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/filters/skcanvas_video_renderer.h" 5 #include "media/filters/skcanvas_video_renderer.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "gpu/GLES2/gl2extchromium.h"
9 #include "gpu/command_buffer/client/gles2_interface.h"
10 #include "gpu/command_buffer/common/mailbox_holder.h"
8 #include "media/base/video_frame.h" 11 #include "media/base/video_frame.h"
9 #include "media/base/yuv_convert.h" 12 #include "media/base/yuv_convert.h"
13 #include "skia/ext/refptr.h"
10 #include "third_party/libyuv/include/libyuv.h" 14 #include "third_party/libyuv/include/libyuv.h"
11 #include "third_party/skia/include/core/SkCanvas.h" 15 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "third_party/skia/include/core/SkImageGenerator.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/SkGrPixelRef.h"
13 #include "ui/gfx/skbitmap_operations.h" 19 #include "ui/gfx/skbitmap_operations.h"
14 20
15 // Skia internal format depends on a platform. On Android it is ABGR, on others 21 // Skia internal format depends on a platform. On Android it is ABGR, on others
16 // it is ARGB. 22 // it is ARGB.
17 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ 23 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
18 SK_A32_SHIFT == 24 24 SK_A32_SHIFT == 24
19 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB 25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
20 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB 26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
21 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ 27 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
22 SK_A32_SHIFT == 24 28 SK_A32_SHIFT == 24
23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR 29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR 30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
25 #else 31 #else
26 #error Unexpected Skia ARGB_8888 layout! 32 #error Unexpected Skia ARGB_8888 layout!
27 #endif 33 #endif
28 34
29 namespace media { 35 namespace media {
30 36
31 static bool IsYUV(media::VideoFrame::Format format) { 37 namespace {
38
39 // This class keeps two temporary resources; software bitmap, hardware bitmap.
40 // If both bitmap are created and then only software bitmap is updated every
41 // frame, hardware bitmap outlives until the media player dies. So we delete
42 // a temporary resource if it is not used for 3 sec.
43 const int kTemporaryResourceDeletionDelay = 3; // Seconds;
scherkus (not reviewing) 2014/10/15 17:10:23 note this is in media time, which has little relat
44
45 bool IsYUV(media::VideoFrame::Format format) {
32 switch (format) { 46 switch (format) {
33 case VideoFrame::YV12: 47 case VideoFrame::YV12:
34 case VideoFrame::YV16: 48 case VideoFrame::YV16:
35 case VideoFrame::I420: 49 case VideoFrame::I420:
36 case VideoFrame::YV12A: 50 case VideoFrame::YV12A:
37 case VideoFrame::YV12J: 51 case VideoFrame::YV12J:
38 case VideoFrame::YV24: 52 case VideoFrame::YV24:
39 case VideoFrame::NV12: 53 case VideoFrame::NV12:
40 return true; 54 return true;
41 case VideoFrame::UNKNOWN: 55 case VideoFrame::UNKNOWN:
42 case VideoFrame::NATIVE_TEXTURE: 56 case VideoFrame::NATIVE_TEXTURE:
43 #if defined(VIDEO_HOLE) 57 #if defined(VIDEO_HOLE)
44 case VideoFrame::HOLE: 58 case VideoFrame::HOLE:
45 #endif // defined(VIDEO_HOLE) 59 #endif // defined(VIDEO_HOLE)
46 return false; 60 return false;
47 } 61 }
48 NOTREACHED() << "Invalid videoframe format provided: " << format; 62 NOTREACHED() << "Invalid videoframe format provided: " << format;
49 return false; 63 return false;
50 } 64 }
51 65
52 static bool IsJPEGColorSpace(media::VideoFrame::Format format) { 66 bool IsJPEGColorSpace(media::VideoFrame::Format format) {
53 switch (format) { 67 switch (format) {
54 case VideoFrame::YV12J: 68 case VideoFrame::YV12J:
55 return true; 69 return true;
56 case VideoFrame::YV12: 70 case VideoFrame::YV12:
57 case VideoFrame::YV16: 71 case VideoFrame::YV16:
58 case VideoFrame::I420: 72 case VideoFrame::I420:
59 case VideoFrame::YV12A: 73 case VideoFrame::YV12A:
60 case VideoFrame::YV24: 74 case VideoFrame::YV24:
61 case VideoFrame::NV12: 75 case VideoFrame::NV12:
62 case VideoFrame::UNKNOWN: 76 case VideoFrame::UNKNOWN:
63 case VideoFrame::NATIVE_TEXTURE: 77 case VideoFrame::NATIVE_TEXTURE:
64 #if defined(VIDEO_HOLE) 78 #if defined(VIDEO_HOLE)
65 case VideoFrame::HOLE: 79 case VideoFrame::HOLE:
66 #endif // defined(VIDEO_HOLE) 80 #endif // defined(VIDEO_HOLE)
67 return false; 81 return false;
68 } 82 }
69 NOTREACHED() << "Invalid videoframe format provided: " << format; 83 NOTREACHED() << "Invalid videoframe format provided: " << format;
70 return false; 84 return false;
71 } 85 }
72 86
73 static bool IsYUVOrNative(media::VideoFrame::Format format) { 87 bool IsYUVOrNative(media::VideoFrame::Format format) {
74 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; 88 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
75 } 89 }
76 90
77 // Converts a |video_frame| to raw |rgb_pixels|. 91 // Converts a |video_frame| to raw |rgb_pixels|.
78 static void ConvertVideoFrameToRGBPixels( 92 void ConvertVideoFrameToRGBPixels(
79 const scoped_refptr<media::VideoFrame>& video_frame, 93 const scoped_refptr<media::VideoFrame>& video_frame,
80 void* rgb_pixels, 94 void* rgb_pixels,
81 size_t row_bytes) { 95 size_t row_bytes) {
82 DCHECK(IsYUVOrNative(video_frame->format())) 96 DCHECK(IsYUVOrNative(video_frame->format()))
83 << video_frame->format(); 97 << video_frame->format();
84 if (IsYUV(video_frame->format())) { 98 if (IsYUV(video_frame->format())) {
85 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), 99 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
86 video_frame->stride(media::VideoFrame::kVPlane)); 100 video_frame->stride(media::VideoFrame::kVPlane));
87 } 101 }
88 102
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 row_bytes); 212 row_bytes);
199 video_frame->ReadPixelsFromNativeTexture(tmp); 213 video_frame->ReadPixelsFromNativeTexture(tmp);
200 break; 214 break;
201 } 215 }
202 default: 216 default:
203 NOTREACHED(); 217 NOTREACHED();
204 break; 218 break;
205 } 219 }
206 } 220 }
207 221
222 bool EnsureTextureBackedSkBitmap(GrContext* gr,
scherkus (not reviewing) 2014/10/15 17:10:23 I know you lifted this code from WebMediaPlayerAnd
223 SkBitmap* bitmap,
224 const gfx::Size& size) {
225 if (!bitmap->getTexture() || bitmap->width() != size.width() ||
226 bitmap->height() != size.height()) {
227 if (!gr)
228 return false;
229 GrTextureDesc desc;
230 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, because
231 // glCopyTextureChromium doesn't support GL_BGRA_EXT as internal format.
232 desc.fConfig = kRGBA_8888_GrPixelConfig;
233 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
234 desc.fSampleCnt = 0;
235 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
236 desc.fWidth = size.width();
237 desc.fHeight = size.height();
238 GrAutoScratchTexture scratch_texture(
239 gr, desc, GrContext::kExact_ScratchTexMatch);
240 skia::RefPtr<GrTexture> texture = skia::AdoptRef(scratch_texture.detach());
241 if (!texture.get())
242 return false;
243
244 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
245 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
246 if (!pixelRef)
247 return false;
248 bitmap->setInfo(info);
249 bitmap->setPixelRef(pixelRef)->unref();
250 }
251
252 return true;
253 }
254
255 bool ConvertVideoFrameToTexture(
scherkus (not reviewing) 2014/10/15 17:10:23 considering all the various combinations of sw vs.
256 VideoFrame* video_frame,
257 SkBitmap* bitmap,
258 SkCanvasVideoRenderer::Context3DProvider* context_provider) {
259 DCHECK(context_provider && context_provider->gl &&
260 context_provider->gr_context &&
261 video_frame->format() == VideoFrame::NATIVE_TEXTURE);
262
263 // Check if we could reuse existing texture based bitmap.
264 // Otherwise, release existing texture based bitmap and allocate
265 // a new one based on video size.
266 if (!EnsureTextureBackedSkBitmap(context_provider->gr_context,
267 bitmap,
268 video_frame->visible_rect().size())) {
269 return false;
270 }
271
272 unsigned textureId =
scherkus (not reviewing) 2014/10/15 17:10:24 textureId -> texture_id
273 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
274 // If CopyVideoFrameToTexture() changes the state of the 'textureId', it's
275 // needed to invalidate the state cached in skia, but currently the state
276 // isn't changed.
277 SkCanvasVideoRenderer::CopyVideoFrameToTexture(context_provider->gl,
278 video_frame,
279 textureId,
280 0,
281 GL_RGBA,
282 GL_UNSIGNED_BYTE,
283 true,
284 false);
285 return true;
286 }
287
288 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
289 public:
290 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
291 virtual ~SyncPointClientImpl() {}
292 virtual uint32 InsertSyncPoint() OVERRIDE {
293 return gl_->InsertSyncPointCHROMIUM();
294 }
295 virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
296 gl_->WaitSyncPointCHROMIUM(sync_point);
297 }
298
299 private:
300 gpu::gles2::GLES2Interface* gl_;
301 };
302
303 bool IsNull(SkCanvasVideoRenderer::Context3DProvider* context_provider) {
304 return !context_provider ||
305 !(context_provider->gl && context_provider->gr_context);
306 }
307
308 } // anonymous namespace
309
208 // Generates an RGB image from a VideoFrame. 310 // Generates an RGB image from a VideoFrame.
209 class VideoImageGenerator : public SkImageGenerator { 311 class VideoImageGenerator : public SkImageGenerator {
210 public: 312 public:
211 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) { 313 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {
212 DCHECK(frame_.get()); 314 DCHECK(frame_.get());
213 } 315 }
214 virtual ~VideoImageGenerator() {} 316 virtual ~VideoImageGenerator() {}
215 317
216 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } 318 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; }
217 319
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 return true; 384 return true;
283 } 385 }
284 386
285 private: 387 private:
286 scoped_refptr<VideoFrame> frame_; 388 scoped_refptr<VideoFrame> frame_;
287 389
288 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); 390 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
289 }; 391 };
290 392
291 SkCanvasVideoRenderer::SkCanvasVideoRenderer() 393 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
292 : generator_(NULL), last_frame_timestamp_(media::kNoTimestamp()) { 394 : generator_(NULL),
395 last_frame_timestamp_(media::kNoTimestamp()),
396 accelerated_last_frame_timestamp_(media::kNoTimestamp()) {
293 last_frame_.setIsVolatile(true); 397 last_frame_.setIsVolatile(true);
294 } 398 }
295 399
296 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} 400 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
297 401
298 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, 402 void SkCanvasVideoRenderer::Paint(
299 SkCanvas* canvas, 403 const scoped_refptr<VideoFrame>& video_frame,
300 const gfx::RectF& dest_rect, 404 SkCanvas* canvas,
301 uint8 alpha, 405 const gfx::RectF& dest_rect,
302 SkXfermode::Mode mode, 406 uint8 alpha,
303 VideoRotation video_rotation) { 407 SkXfermode::Mode mode,
408 VideoRotation video_rotation,
409 SkCanvasVideoRenderer::Context3DProvider* context_provider) {
scherkus (not reviewing) 2014/10/15 17:10:23 we can drop SkCanvasVideoRenderer::, right?
304 if (alpha == 0) { 410 if (alpha == 0) {
305 return; 411 return;
306 } 412 }
307 413
308 SkRect dest; 414 SkRect dest;
309 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); 415 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
310 416
311 SkPaint paint; 417 SkPaint paint;
312 paint.setAlpha(alpha); 418 paint.setAlpha(alpha);
313 419
314 // Paint black rectangle if there isn't a frame available or the 420 // Paint black rectangle if there isn't a frame available or the
315 // frame has an unexpected format. 421 // frame has an unexpected format.
316 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { 422 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
423 !IsYUVOrNative(video_frame->format())) {
317 canvas->drawRect(dest, paint); 424 canvas->drawRect(dest, paint);
318 canvas->flush(); 425 canvas->flush();
319 return; 426 return;
320 } 427 }
321 428
429 bool accelerated = false;
430 if (!IsNull(context_provider) &&
431 video_frame->format() == media::VideoFrame::NATIVE_TEXTURE &&
432 canvas->getGrContext()) {
433 // TODO(dshwang): Android video decoder doesn't update the timestamp on a
434 // VideoFrame. To reduce redundant copy, Android should update the
435 // timestamp.
436 if (accelerated_last_frame_.isNull() ||
437 video_frame->timestamp() != accelerated_last_frame_timestamp_ ||
438 video_frame->timestamp() == base::TimeDelta()) {
439 accelerated = ConvertVideoFrameToTexture(
440 video_frame.get(), &accelerated_last_frame_, context_provider);
441 if (accelerated)
442 accelerated_last_frame_timestamp_ = video_frame->timestamp();
443 } else {
444 DCHECK(accelerated_last_frame_.getTexture());
445 accelerated = true;
446 }
447 }
448
322 // Check if we should convert and update |last_frame_|. 449 // Check if we should convert and update |last_frame_|.
323 if (last_frame_.isNull() || 450 if (!accelerated) {
324 video_frame->timestamp() != last_frame_timestamp_) { 451 if (last_frame_.isNull() ||
325 generator_ = new VideoImageGenerator(video_frame); 452 video_frame->timestamp() != last_frame_timestamp_) {
453 generator_ = new VideoImageGenerator(video_frame);
326 454
327 // Note: This takes ownership of |generator_|. 455 // Note: This takes ownership of |generator_|.
328 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { 456 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) {
329 NOTREACHED(); 457 NOTREACHED();
458 }
459 DCHECK(video_frame->visible_rect().width() == last_frame_.width() &&
460 video_frame->visible_rect().height() == last_frame_.height());
461
462 last_frame_timestamp_ = video_frame->timestamp();
463 } else if (generator_) {
464 generator_->set_frame(video_frame);
330 } 465 }
331 DCHECK(video_frame->visible_rect().width() == last_frame_.width() &&
332 video_frame->visible_rect().height() == last_frame_.height());
333
334 last_frame_timestamp_ = video_frame->timestamp();
335 } else if (generator_) {
336 generator_->set_frame(video_frame);
337 } 466 }
338 467
339 paint.setXfermodeMode(mode); 468 paint.setXfermodeMode(mode);
340 paint.setFilterLevel(SkPaint::kLow_FilterLevel); 469 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
341 470
471 SkBitmap& target_frame = accelerated ? accelerated_last_frame_ : last_frame_;
342 bool need_transform = 472 bool need_transform =
343 video_rotation != VIDEO_ROTATION_0 || 473 video_rotation != VIDEO_ROTATION_0 ||
344 dest_rect.size() != video_frame->visible_rect().size() || 474 dest_rect.size() != video_frame->visible_rect().size() ||
345 !dest_rect.origin().IsOrigin(); 475 !dest_rect.origin().IsOrigin();
346 if (need_transform) { 476 if (need_transform) {
347 canvas->save(); 477 canvas->save();
348 canvas->translate( 478 canvas->translate(
349 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)), 479 SkFloatToScalar(dest_rect.x() + (dest_rect.width() * 0.5f)),
350 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f))); 480 SkFloatToScalar(dest_rect.y() + (dest_rect.height() * 0.5f)));
351 SkScalar angle = SkFloatToScalar(0.0f); 481 SkScalar angle = SkFloatToScalar(0.0f);
(...skipping 12 matching lines...) Expand all
364 } 494 }
365 canvas->rotate(angle); 495 canvas->rotate(angle);
366 496
367 gfx::SizeF rotated_dest_size = dest_rect.size(); 497 gfx::SizeF rotated_dest_size = dest_rect.size();
368 if (video_rotation == VIDEO_ROTATION_90 || 498 if (video_rotation == VIDEO_ROTATION_90 ||
369 video_rotation == VIDEO_ROTATION_270) { 499 video_rotation == VIDEO_ROTATION_270) {
370 rotated_dest_size = 500 rotated_dest_size =
371 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); 501 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
372 } 502 }
373 canvas->scale( 503 canvas->scale(
374 SkFloatToScalar(rotated_dest_size.width() / last_frame_.width()), 504 SkFloatToScalar(rotated_dest_size.width() / target_frame.width()),
375 SkFloatToScalar(rotated_dest_size.height() / last_frame_.height())); 505 SkFloatToScalar(rotated_dest_size.height() / target_frame.height()));
376 canvas->translate(-SkFloatToScalar(last_frame_.width() * 0.5f), 506 canvas->translate(-SkFloatToScalar(target_frame.width() * 0.5f),
377 -SkFloatToScalar(last_frame_.height() * 0.5f)); 507 -SkFloatToScalar(target_frame.height() * 0.5f));
378 } 508 }
379 canvas->drawBitmap(last_frame_, 0, 0, &paint); 509 canvas->drawBitmap(target_frame, 0, 0, &paint);
380 if (need_transform) 510 if (need_transform)
381 canvas->restore(); 511 canvas->restore();
382 canvas->flush(); 512 canvas->flush();
383 // SkCanvas::flush() causes the generator to generate SkImage, so delete 513 // SkCanvas::flush() causes the generator to generate SkImage, so delete
384 // |video_frame| not to be outlived. 514 // |video_frame| not to be outlived.
385 if (generator_) 515 if (generator_)
386 generator_->set_frame(NULL); 516 generator_->set_frame(NULL);
517 CleanUpTemporaryBuffers();
387 } 518 }
388 519
389 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, 520 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
390 SkCanvas* canvas) { 521 SkCanvas* canvas) {
391 Paint(video_frame, 522 Paint(video_frame,
392 canvas, 523 canvas,
393 video_frame->visible_rect(), 524 video_frame->visible_rect(),
394 0xff, 525 0xff,
395 SkXfermode::kSrc_Mode, 526 SkXfermode::kSrc_Mode,
396 media::VIDEO_ROTATION_0); 527 media::VIDEO_ROTATION_0,
528 NULL);
529 }
530
531 void SkCanvasVideoRenderer::CleanUpTemporaryBuffers() {
532 static const base::TimeDelta buffer_time =
533 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay);
534 // Find the latest time stamp.
535 base::TimeDelta last_timestamp =
536 accelerated_last_frame_timestamp_ > last_frame_timestamp_
537 ? accelerated_last_frame_timestamp_
538 : last_frame_timestamp_;
539 // Delete a too old resource.
540 if (last_timestamp > last_frame_timestamp_ + buffer_time &&
541 !last_frame_.isNull()) {
542 last_frame_.reset();
543 }
544 if (last_timestamp > accelerated_last_frame_timestamp_ + buffer_time &&
545 !accelerated_last_frame_.isNull()) {
546 accelerated_last_frame_.reset();
547 }
548 }
549
550 // static
551 void SkCanvasVideoRenderer::CopyVideoFrameToTexture(
scherkus (not reviewing) 2014/10/15 17:10:23 ditto for precise naming this is much more like C
552 gpu::gles2::GLES2Interface* gl,
553 VideoFrame* video_frame,
554 unsigned int texture,
555 unsigned int level,
556 unsigned int internal_format,
557 unsigned int type,
558 bool premultiply_alpha,
559 bool flip_y) {
560 DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE);
561 const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
562 DCHECK(mailbox_holder->texture_target == GL_TEXTURE_2D ||
563 mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES);
564
565 gl->WaitSyncPointCHROMIUM(mailbox_holder->sync_point);
566 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
567 mailbox_holder->texture_target, mailbox_holder->mailbox.name);
568
569 // The video is stored in a unmultiplied format, so premultiply
570 // if necessary.
571 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha);
572 // Application itself needs to take care of setting the right |flip_y|
573 // value down to get the expected result.
574 // "flip_y == true" means to reverse the video orientation while
575 // "flip_y == false" means to keep the intrinsic orientation.
576 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
577 gl->CopyTextureCHROMIUM(
578 GL_TEXTURE_2D, source_texture, texture, level, internal_format, type);
579 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
580 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
581
582 gl->DeleteTextures(1, &source_texture);
583 gl->Flush();
584
585 SyncPointClientImpl client(gl);
586 video_frame->UpdateReleaseSyncPoint(&client);
397 } 587 }
398 588
399 } // namespace media 589 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698