Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/blink/skcanvas_video_renderer.h" | 5 #include "media/blink/skcanvas_video_renderer.h" |
| 6 | 6 |
| 7 #include "gpu/GLES2/gl2extchromium.h" | 7 #include "gpu/GLES2/gl2extchromium.h" |
| 8 #include "gpu/command_buffer/client/gles2_interface.h" | 8 #include "gpu/command_buffer/client/gles2_interface.h" |
| 9 #include "gpu/command_buffer/common/mailbox_holder.h" | 9 #include "gpu/command_buffer/common/mailbox_holder.h" |
| 10 #include "media/base/video_frame.h" | 10 #include "media/base/video_frame.h" |
| 11 #include "media/base/yuv_convert.h" | 11 #include "media/base/yuv_convert.h" |
| 12 #include "skia/ext/refptr.h" | 12 #include "skia/ext/refptr.h" |
| 13 #include "third_party/libyuv/include/libyuv.h" | 13 #include "third_party/libyuv/include/libyuv.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" | 14 #include "third_party/skia/include/core/SkCanvas.h" |
| 15 #include "third_party/skia/include/core/SkImage.h" | |
| 15 #include "third_party/skia/include/core/SkImageGenerator.h" | 16 #include "third_party/skia/include/core/SkImageGenerator.h" |
| 16 #include "third_party/skia/include/gpu/GrContext.h" | 17 #include "third_party/skia/include/gpu/GrContext.h" |
| 17 #include "third_party/skia/include/gpu/GrTextureProvider.h" | 18 #include "third_party/skia/include/gpu/GrTextureProvider.h" |
| 18 #include "third_party/skia/include/gpu/SkGrPixelRef.h" | 19 #include "third_party/skia/include/gpu/SkGrPixelRef.h" |
| 19 #include "ui/gfx/skbitmap_operations.h" | |
| 20 | 20 |
| 21 // 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 |
| 22 // it is ARGB. | 22 // it is ARGB. |
| 23 #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 && \ |
| 24 SK_A32_SHIFT == 24 | 24 SK_A32_SHIFT == 24 |
| 25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB | 25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB |
| 26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB | 26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB |
| 27 #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 && \ |
| 28 SK_A32_SHIFT == 24 | 28 SK_A32_SHIFT == 24 |
| 29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR | 29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR |
| 30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR | 30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR |
| 31 #else | 31 #else |
| 32 #error Unexpected Skia ARGB_8888 layout! | 32 #error Unexpected Skia ARGB_8888 layout! |
| 33 #endif | 33 #endif |
| 34 | 34 |
| 35 namespace media { | 35 namespace media { |
| 36 | 36 |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 // This class keeps two temporary resources; software bitmap, hardware bitmap. | 39 bool IsCanvasDrawingOnPicture(SkCanvas* canvas) { |
| 40 // If both bitmap are created and then only software bitmap is updated every | 40 SkImageInfo info; |
| 41 // frame, hardware bitmap outlives until the media player dies. So we delete | 41 size_t rowBytes; |
| 42 // a temporary resource if it is not used for 3 sec. | 42 return !canvas->getGrContext() && !canvas->peekPixels(&info, &rowBytes); |
| 43 const int kTemporaryResourceDeletionDelay = 3; // Seconds; | 43 } |
| 44 | 44 |
| 45 bool IsYUV(media::VideoFrame::Format format) { | 45 bool IsYUV(media::VideoFrame::Format format) { |
| 46 switch (format) { | 46 switch (format) { |
| 47 case VideoFrame::YV12: | 47 case VideoFrame::YV12: |
| 48 case VideoFrame::YV16: | 48 case VideoFrame::YV16: |
| 49 case VideoFrame::I420: | 49 case VideoFrame::I420: |
| 50 case VideoFrame::YV12A: | 50 case VideoFrame::YV12A: |
| 51 case VideoFrame::YV24: | 51 case VideoFrame::YV24: |
| 52 case VideoFrame::NV12: | 52 case VideoFrame::NV12: |
| 53 return true; | 53 return true; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 68 int result; | 68 int result; |
| 69 return video_frame->metadata()->GetInteger( | 69 return video_frame->metadata()->GetInteger( |
| 70 media::VideoFrameMetadata::COLOR_SPACE, &result) && | 70 media::VideoFrameMetadata::COLOR_SPACE, &result) && |
| 71 result == color_space; | 71 result == color_space; |
| 72 } | 72 } |
| 73 | 73 |
| 74 bool IsYUVOrNative(media::VideoFrame::Format format) { | 74 bool IsYUVOrNative(media::VideoFrame::Format format) { |
| 75 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; | 75 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
| 76 } | 76 } |
| 77 | 77 |
| 78 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap, | |
| 79 const gfx::Size& size) { | |
| 80 return bitmap->getTexture() && bitmap->width() == size.width() && | |
| 81 bitmap->height() == size.height(); | |
| 82 } | |
| 83 | |
| 84 bool AllocateSkBitmapTexture(GrContext* gr, | |
| 85 SkBitmap* bitmap, | |
| 86 const gfx::Size& size) { | |
| 87 DCHECK(gr); | |
| 88 GrTextureDesc desc; | |
| 89 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid | |
| 90 // RGBA to BGRA conversion. | |
| 91 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
| 92 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
| 93 desc.fSampleCnt = 0; | |
| 94 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 95 desc.fWidth = size.width(); | |
| 96 desc.fHeight = size.height(); | |
| 97 skia::RefPtr<GrTexture> texture = skia::AdoptRef( | |
| 98 gr->textureProvider()->refScratchTexture( | |
| 99 desc, GrTextureProvider::kExact_ScratchTexMatch)); | |
| 100 if (!texture.get()) | |
| 101 return false; | |
| 102 | |
| 103 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight); | |
| 104 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get())); | |
| 105 if (!pixel_ref) | |
| 106 return false; | |
| 107 bitmap->setInfo(info); | |
| 108 bitmap->setPixelRef(pixel_ref)->unref(); | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame, | |
| 113 SkBitmap* bitmap, | |
| 114 const Context3D& context_3d) { | |
| 115 // Check if we could reuse existing texture based bitmap. | |
| 116 // Otherwise, release existing texture based bitmap and allocate | |
| 117 // a new one based on video size. | |
| 118 if (!IsSkBitmapProperlySizedTexture(bitmap, | |
| 119 video_frame->visible_rect().size())) { | |
| 120 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, | |
| 121 video_frame->visible_rect().size())) { | |
| 122 return false; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 unsigned texture_id = | |
| 127 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); | |
| 128 // If CopyVideoFrameTextureToGLTexture() changes the state of the | |
| 129 // |texture_id|, it's needed to invalidate the state cached in skia, | |
| 130 // but currently the state isn't changed. | |
| 131 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | |
| 132 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, | |
| 133 false); | |
| 134 bitmap->notifyPixelsChanged(); | |
| 135 return true; | |
| 136 } | |
| 137 | |
| 138 class SyncPointClientImpl : public VideoFrame::SyncPointClient { | 78 class SyncPointClientImpl : public VideoFrame::SyncPointClient { |
| 139 public: | 79 public: |
| 140 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} | 80 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} |
| 141 ~SyncPointClientImpl() override {} | 81 ~SyncPointClientImpl() override {} |
| 142 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } | 82 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } |
| 143 void WaitSyncPoint(uint32 sync_point) override { | 83 void WaitSyncPoint(uint32 sync_point) override { |
| 144 gl_->WaitSyncPointCHROMIUM(sync_point); | 84 gl_->WaitSyncPointCHROMIUM(sync_point); |
| 145 } | 85 } |
| 146 | 86 |
| 147 private: | 87 private: |
| 148 gpu::gles2::GLES2Interface* gl_; | 88 gpu::gles2::GLES2Interface* gl_; |
| 149 | 89 |
| 150 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); | 90 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); |
| 151 }; | 91 }; |
| 152 | 92 |
| 93 // Creates a SkImage from a |video_frame| backed by native resources. | |
| 94 // The SkImage will not take ownership of the underlying resources and the | |
| 95 // caller will have to delete them after the SkImage is used. | |
| 96 // |source_textures| is a pointer to an array that will be filled with | |
| 97 // texture ids backing the returned image. | |
| 98 SkImage* NewSkImageFromVideoFrameNative( | |
| 99 const scoped_refptr<VideoFrame>& video_frame, | |
| 100 const Context3D& context_3d, | |
| 101 unsigned* source_textures) { | |
| 102 // TODO(dcastagna): Add support for YUV420. | |
| 103 DCHECK_EQ(VideoFrame::TEXTURE_RGBA, video_frame->texture_format()); | |
| 104 | |
| 105 // Get the texture from the mailbox and wrap it in a GrTexture. | |
| 106 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | |
| 107 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | |
| 108 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | |
| 109 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES); | |
|
DaleCurtis
2015/05/27 22:37:16
Add << texture_target?
Daniele Castagna
2015/05/28 22:48:12
Done.
| |
| 110 gpu::gles2::GLES2Interface* gl = context_3d.gl; | |
| 111 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); | |
| 112 *source_textures = gl->CreateAndConsumeTextureCHROMIUM( | |
| 113 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | |
|
dshwang
2015/05/28 15:54:17
Need to insert new sync point so that GpuVideoDeco
Daniele Castagna
2015/05/28 22:48:12
We keep a scoped_refptr to the VideoFrame, the Gpu
dshwang
2015/05/29 08:49:46
That's true in Renderer, but it's not true in GPU
Daniele Castagna
2015/06/05 04:15:31
Context A can delete the texture name whenever it
| |
| 114 GrBackendTextureDesc desc; | |
| 115 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 116 desc.fWidth = video_frame->coded_size().width(); | |
| 117 desc.fHeight = video_frame->coded_size().height(); | |
| 118 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
| 119 desc.fTextureHandle = *source_textures; | |
| 120 return SkImage::NewFromTexture(context_3d.gr_context, desc); | |
| 121 } | |
| 122 | |
| 153 } // anonymous namespace | 123 } // anonymous namespace |
| 154 | 124 |
| 155 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. | 125 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. |
| 156 class VideoImageGenerator : public SkImageGenerator { | 126 class VideoImageGenerator : public SkImageGenerator { |
| 157 public: | 127 public: |
| 158 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) | 128 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) |
| 159 : SkImageGenerator( | 129 : SkImageGenerator( |
| 160 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), | 130 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), |
| 161 frame->visible_rect().height())) | 131 frame->visible_rect().height())) |
| 162 , frame_(frame) { | 132 , frame_(frame) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 } | 218 } |
| 249 return true; | 219 return true; |
| 250 } | 220 } |
| 251 | 221 |
| 252 private: | 222 private: |
| 253 scoped_refptr<VideoFrame> frame_; | 223 scoped_refptr<VideoFrame> frame_; |
| 254 | 224 |
| 255 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); | 225 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); |
| 256 }; | 226 }; |
| 257 | 227 |
| 258 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 228 SkCanvasVideoRenderer::SkCanvasVideoRenderer() { |
| 259 : last_frame_timestamp_(media::kNoTimestamp()), | |
| 260 frame_deleting_timer_( | |
| 261 FROM_HERE, | |
| 262 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay), | |
| 263 this, | |
| 264 &SkCanvasVideoRenderer::ResetLastFrame), | |
| 265 accelerated_generator_(nullptr), | |
| 266 accelerated_last_frame_timestamp_(media::kNoTimestamp()), | |
| 267 accelerated_frame_deleting_timer_( | |
| 268 FROM_HERE, | |
| 269 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay), | |
| 270 this, | |
| 271 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame) { | |
| 272 last_frame_.setIsVolatile(true); | |
| 273 } | 229 } |
| 274 | 230 |
| 275 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 231 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() { |
| 232 } | |
| 276 | 233 |
| 277 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, | 234 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
| 278 SkCanvas* canvas, | 235 SkCanvas* canvas, |
| 279 const gfx::RectF& dest_rect, | 236 const gfx::RectF& dest_rect, |
| 280 uint8 alpha, | 237 uint8 alpha, |
| 281 SkXfermode::Mode mode, | 238 SkXfermode::Mode mode, |
| 282 VideoRotation video_rotation, | 239 VideoRotation video_rotation, |
| 283 const Context3D& context_3d) { | 240 const Context3D& context_3d) { |
| 284 if (alpha == 0) { | 241 if (alpha == 0) { |
| 285 return; | 242 return; |
| 286 } | 243 } |
| 287 | 244 |
| 288 SkRect dest; | 245 SkRect dest; |
| 289 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 246 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
| 290 | 247 |
| 291 SkPaint paint; | 248 SkPaint paint; |
| 292 paint.setAlpha(alpha); | 249 paint.setAlpha(alpha); |
| 293 | 250 |
| 294 // Paint black rectangle if there isn't a frame available or the | 251 // Paint black rectangle if there isn't a frame available or the |
| 295 // frame has an unexpected format. | 252 // frame has an unexpected format. |
| 296 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || | 253 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || |
| 297 !IsYUVOrNative(video_frame->format())) { | 254 !IsYUVOrNative(video_frame->format())) { |
| 298 canvas->drawRect(dest, paint); | 255 canvas->drawRect(dest, paint); |
| 299 canvas->flush(); | 256 canvas->flush(); |
| 300 return; | 257 return; |
| 301 } | 258 } |
| 302 | 259 |
| 303 SkBitmap* target_frame = nullptr; | 260 unsigned texture_id = 0; |
| 304 | 261 SkImage* target_frame = nullptr; |
|
dshwang
2015/05/28 15:54:17
use skia::RefPtr<SkImage>
Daniele Castagna
2015/05/28 22:48:12
Done.
| |
| 305 if (video_frame->format() == VideoFrame::NATIVE_TEXTURE) { | 262 if (video_frame->format() == VideoFrame::NATIVE_TEXTURE) { |
| 306 // Draw HW Video on both SW and HW Canvas. | 263 DCHECK(context_3d.gr_context); |
| 307 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. | 264 DCHECK(context_3d.gl); |
| 308 if (accelerated_last_frame_.isNull() || | 265 target_frame = |
| 309 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 266 NewSkImageFromVideoFrameNative(video_frame, context_3d, &texture_id); |
| 310 DCHECK(context_3d.gl); | |
| 311 DCHECK(context_3d.gr_context); | |
| 312 if (accelerated_generator_) { | |
| 313 // Reset SkBitmap used in SWVideo-to-HWCanvas path. | |
| 314 accelerated_last_frame_.reset(); | |
| 315 accelerated_generator_ = nullptr; | |
| 316 } | |
| 317 if (!CopyVideoFrameTextureToSkBitmapTexture( | |
| 318 video_frame.get(), &accelerated_last_frame_, context_3d)) { | |
| 319 NOTREACHED(); | |
| 320 return; | |
| 321 } | |
| 322 DCHECK(video_frame->visible_rect().width() == | |
| 323 accelerated_last_frame_.width() && | |
| 324 video_frame->visible_rect().height() == | |
| 325 accelerated_last_frame_.height()); | |
| 326 | |
| 327 accelerated_last_frame_timestamp_ = video_frame->timestamp(); | |
| 328 } | |
| 329 target_frame = &accelerated_last_frame_; | |
| 330 accelerated_frame_deleting_timer_.Reset(); | |
| 331 } else if (canvas->getGrContext()) { | |
| 332 DCHECK(video_frame->format() != VideoFrame::NATIVE_TEXTURE); | |
| 333 if (accelerated_last_frame_.isNull() || | |
| 334 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | |
| 335 // Draw SW Video on HW Canvas. | |
| 336 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) { | |
| 337 // Reset SkBitmap used in HWVideo-to-HWCanvas path. | |
| 338 accelerated_last_frame_.reset(); | |
| 339 } | |
| 340 accelerated_generator_ = new VideoImageGenerator(video_frame); | |
| 341 | |
| 342 // Note: This takes ownership of |accelerated_generator_|. | |
| 343 if (!SkInstallDiscardablePixelRef(accelerated_generator_, | |
| 344 &accelerated_last_frame_)) { | |
| 345 NOTREACHED(); | |
| 346 return; | |
| 347 } | |
| 348 DCHECK(video_frame->visible_rect().width() == | |
| 349 accelerated_last_frame_.width() && | |
| 350 video_frame->visible_rect().height() == | |
| 351 accelerated_last_frame_.height()); | |
| 352 | |
| 353 accelerated_last_frame_timestamp_ = video_frame->timestamp(); | |
| 354 } else if (accelerated_generator_) { | |
| 355 accelerated_generator_->set_frame(video_frame); | |
| 356 } | |
| 357 target_frame = &accelerated_last_frame_; | |
| 358 accelerated_frame_deleting_timer_.Reset(); | |
| 359 } else { | 267 } else { |
| 360 // Draw SW Video on SW Canvas. | 268 VideoImageGenerator* generator = new VideoImageGenerator(video_frame); |
| 361 DCHECK(video_frame->format() != VideoFrame::NATIVE_TEXTURE); | 269 target_frame = SkImage::NewFromGenerator(generator); |
| 362 if (last_frame_.isNull() || | |
| 363 video_frame->timestamp() != last_frame_timestamp_) { | |
| 364 // Check if |bitmap| needs to be (re)allocated. | |
| 365 if (last_frame_.isNull() || | |
| 366 last_frame_.width() != video_frame->visible_rect().width() || | |
| 367 last_frame_.height() != video_frame->visible_rect().height()) { | |
| 368 last_frame_.allocN32Pixels(video_frame->visible_rect().width(), | |
| 369 video_frame->visible_rect().height()); | |
| 370 last_frame_.setIsVolatile(true); | |
| 371 } | |
| 372 last_frame_.lockPixels(); | |
| 373 ConvertVideoFrameToRGBPixels( | |
| 374 video_frame, last_frame_.getPixels(), last_frame_.rowBytes()); | |
| 375 last_frame_.notifyPixelsChanged(); | |
| 376 last_frame_.unlockPixels(); | |
| 377 last_frame_timestamp_ = video_frame->timestamp(); | |
| 378 } | |
| 379 target_frame = &last_frame_; | |
| 380 frame_deleting_timer_.Reset(); | |
| 381 } | 270 } |
| 382 | 271 |
| 383 paint.setXfermodeMode(mode); | 272 paint.setXfermodeMode(mode); |
| 384 paint.setFilterQuality(kLow_SkFilterQuality); | 273 paint.setFilterQuality(kLow_SkFilterQuality); |
| 385 | 274 |
| 386 bool need_transform = | 275 bool need_transform = |
| 387 video_rotation != VIDEO_ROTATION_0 || | 276 video_rotation != VIDEO_ROTATION_0 || |
| 388 dest_rect.size() != video_frame->visible_rect().size() || | 277 dest_rect.size() != video_frame->visible_rect().size() || |
| 389 !dest_rect.origin().IsOrigin(); | 278 !dest_rect.origin().IsOrigin(); |
| 390 if (need_transform) { | 279 if (need_transform) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 413 video_rotation == VIDEO_ROTATION_270) { | 302 video_rotation == VIDEO_ROTATION_270) { |
| 414 rotated_dest_size = | 303 rotated_dest_size = |
| 415 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 304 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
| 416 } | 305 } |
| 417 canvas->scale( | 306 canvas->scale( |
| 418 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), | 307 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), |
| 419 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); | 308 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); |
| 420 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), | 309 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
| 421 -SkFloatToScalar(target_frame->height() * 0.5f)); | 310 -SkFloatToScalar(target_frame->height() * 0.5f)); |
| 422 } | 311 } |
| 423 canvas->drawBitmap(*target_frame, 0, 0, &paint); | 312 canvas->drawImage(target_frame, 0, 0, &paint); |
| 424 if (need_transform) | 313 if (need_transform) |
| 425 canvas->restore(); | 314 canvas->restore(); |
| 426 canvas->flush(); | 315 canvas->flush(); |
| 427 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 316 SkSafeSetNull(target_frame); |
| 428 // |video_frame| not to be outlived. | 317 // When target_frame is created from a backend texture, calling |
| 429 if (canvas->getGrContext() && accelerated_generator_) | 318 // textureSkCanvas::flush() causes Skia to use all the resources backing the |
| 430 accelerated_generator_->set_frame(nullptr); | 319 // SkImage and the underlying texture can be delete. |
| 320 // TODO(dcastagna): release the texture in a callback once Skia API exposes | |
| 321 // the functionality. | |
| 322 if (texture_id) { | |
| 323 DCHECK(!IsCanvasDrawingOnPicture(canvas)); | |
| 324 DCHECK(context_3d.gl); | |
| 325 context_3d.gl->DeleteTextures(1, &texture_id); | |
| 326 } | |
| 431 } | 327 } |
| 432 | 328 |
| 433 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 329 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
| 434 SkCanvas* canvas, | 330 SkCanvas* canvas, |
| 435 const Context3D& context_3d) { | 331 const Context3D& context_3d) { |
| 436 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, | 332 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, |
| 437 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); | 333 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); |
| 438 } | 334 } |
| 439 | 335 |
| 440 // static | 336 // static |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); | 503 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); |
| 608 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); | 504 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); |
| 609 | 505 |
| 610 gl->DeleteTextures(1, &source_texture); | 506 gl->DeleteTextures(1, &source_texture); |
| 611 gl->Flush(); | 507 gl->Flush(); |
| 612 | 508 |
| 613 SyncPointClientImpl client(gl); | 509 SyncPointClientImpl client(gl); |
| 614 video_frame->UpdateReleaseSyncPoint(&client); | 510 video_frame->UpdateReleaseSyncPoint(&client); |
| 615 } | 511 } |
| 616 | 512 |
| 617 void SkCanvasVideoRenderer::ResetLastFrame() { | |
| 618 last_frame_.reset(); | |
| 619 last_frame_timestamp_ = media::kNoTimestamp(); | |
| 620 } | |
| 621 | |
| 622 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { | |
| 623 accelerated_last_frame_.reset(); | |
| 624 accelerated_generator_ = nullptr; | |
| 625 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); | |
| 626 } | |
| 627 | |
| 628 } // namespace media | 513 } // namespace media |
| OLD | NEW |