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 skia::RefPtr<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) | |
|
dshwang
2015/05/29 08:49:47
Can SkImage wrap RECTANBLE_ARB and EXTERNAL_OES al
dshwang
2015/05/29 17:30:30
skia doesn't support RECTANBLE_ARB and EXTERNAL_OE
Daniele Castagna
2015/06/05 04:15:31
This happened to work for texture_rectangle. :/
Br
| |
| 110 << mailbox_holder.texture_target; | |
| 111 gpu::gles2::GLES2Interface* gl = context_3d.gl; | |
| 112 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); | |
| 113 *source_textures = gl->CreateAndConsumeTextureCHROMIUM( | |
| 114 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | |
| 115 GrBackendTextureDesc desc; | |
| 116 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 117 desc.fWidth = video_frame->coded_size().width(); | |
| 118 desc.fHeight = video_frame->coded_size().height(); | |
| 119 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
| 120 desc.fTextureHandle = *source_textures; | |
| 121 return skia::AdoptRef(SkImage::NewFromTexture(context_3d.gr_context, desc)); | |
| 122 } | |
| 123 | |
| 153 } // anonymous namespace | 124 } // anonymous namespace |
| 154 | 125 |
| 155 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. | 126 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. |
| 156 class VideoImageGenerator : public SkImageGenerator { | 127 class VideoImageGenerator : public SkImageGenerator { |
| 157 public: | 128 public: |
| 158 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) | 129 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) |
| 159 : SkImageGenerator( | 130 : SkImageGenerator( |
| 160 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), | 131 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), |
| 161 frame->visible_rect().height())) | 132 frame->visible_rect().height())) |
| 162 , frame_(frame) { | 133 , frame_(frame) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 } | 219 } |
| 249 return true; | 220 return true; |
| 250 } | 221 } |
| 251 | 222 |
| 252 private: | 223 private: |
| 253 scoped_refptr<VideoFrame> frame_; | 224 scoped_refptr<VideoFrame> frame_; |
| 254 | 225 |
| 255 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); | 226 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); |
| 256 }; | 227 }; |
| 257 | 228 |
| 258 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 229 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 } | 230 } |
| 274 | 231 |
| 275 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 232 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() { |
| 233 } | |
| 276 | 234 |
| 277 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, | 235 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
| 278 SkCanvas* canvas, | 236 SkCanvas* canvas, |
| 279 const gfx::RectF& dest_rect, | 237 const gfx::RectF& dest_rect, |
| 280 uint8 alpha, | 238 uint8 alpha, |
| 281 SkXfermode::Mode mode, | 239 SkXfermode::Mode mode, |
| 282 VideoRotation video_rotation, | 240 VideoRotation video_rotation, |
| 283 const Context3D& context_3d) { | 241 const Context3D& context_3d) { |
| 284 if (alpha == 0) { | 242 if (alpha == 0) { |
| 285 return; | 243 return; |
| 286 } | 244 } |
| 287 | 245 |
| 288 SkRect dest; | 246 SkRect dest; |
| 289 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 247 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
| 290 | 248 |
| 291 SkPaint paint; | 249 SkPaint paint; |
| 292 paint.setAlpha(alpha); | 250 paint.setAlpha(alpha); |
| 293 | 251 |
| 294 // Paint black rectangle if there isn't a frame available or the | 252 // Paint black rectangle if there isn't a frame available or the |
| 295 // frame has an unexpected format. | 253 // frame has an unexpected format. |
| 296 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || | 254 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || |
| 297 !IsYUVOrNative(video_frame->format())) { | 255 !IsYUVOrNative(video_frame->format())) { |
| 298 canvas->drawRect(dest, paint); | 256 canvas->drawRect(dest, paint); |
| 299 canvas->flush(); | 257 canvas->flush(); |
| 300 return; | 258 return; |
| 301 } | 259 } |
| 302 | 260 |
| 303 SkBitmap* target_frame = nullptr; | 261 unsigned texture_id = 0; |
| 304 | 262 skia::RefPtr<SkImage> target_frame; |
| 305 if (video_frame->format() == VideoFrame::NATIVE_TEXTURE) { | 263 if (video_frame->format() == VideoFrame::NATIVE_TEXTURE) { |
| 306 // Draw HW Video on both SW and HW Canvas. | 264 DCHECK(context_3d.gr_context); |
| 307 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. | 265 DCHECK(context_3d.gl); |
| 308 if (accelerated_last_frame_.isNull() || | 266 target_frame = |
| 309 video_frame->timestamp() != accelerated_last_frame_timestamp_) { | 267 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 { | 268 } else { |
| 360 // Draw SW Video on SW Canvas. | 269 VideoImageGenerator* generator = new VideoImageGenerator(video_frame); |
| 361 DCHECK(video_frame->format() != VideoFrame::NATIVE_TEXTURE); | 270 target_frame = skia::AdoptRef(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 } | 271 } |
| 382 | 272 |
| 383 paint.setXfermodeMode(mode); | 273 paint.setXfermodeMode(mode); |
| 384 paint.setFilterQuality(kLow_SkFilterQuality); | 274 paint.setFilterQuality(kLow_SkFilterQuality); |
| 385 | 275 |
| 386 bool need_transform = | 276 bool need_transform = |
| 387 video_rotation != VIDEO_ROTATION_0 || | 277 video_rotation != VIDEO_ROTATION_0 || |
| 388 dest_rect.size() != video_frame->visible_rect().size() || | 278 dest_rect.size() != video_frame->visible_rect().size() || |
| 389 !dest_rect.origin().IsOrigin(); | 279 !dest_rect.origin().IsOrigin(); |
| 390 if (need_transform) { | 280 if (need_transform) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 413 video_rotation == VIDEO_ROTATION_270) { | 303 video_rotation == VIDEO_ROTATION_270) { |
| 414 rotated_dest_size = | 304 rotated_dest_size = |
| 415 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); | 305 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); |
| 416 } | 306 } |
| 417 canvas->scale( | 307 canvas->scale( |
| 418 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), | 308 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), |
| 419 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); | 309 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); |
| 420 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), | 310 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
| 421 -SkFloatToScalar(target_frame->height() * 0.5f)); | 311 -SkFloatToScalar(target_frame->height() * 0.5f)); |
| 422 } | 312 } |
| 423 canvas->drawBitmap(*target_frame, 0, 0, &paint); | 313 canvas->drawImage(target_frame.get(), 0, 0, &paint); |
| 424 if (need_transform) | 314 if (need_transform) |
| 425 canvas->restore(); | 315 canvas->restore(); |
| 426 canvas->flush(); | 316 canvas->flush(); |
| 427 // SkCanvas::flush() causes the generator to generate SkImage, so delete | 317 target_frame.clear(); |
| 428 // |video_frame| not to be outlived. | 318 // When target_frame is created from a backend texture, calling |
| 429 if (canvas->getGrContext() && accelerated_generator_) | 319 // textureSkCanvas::flush() causes Skia to use all the resources backing the |
| 430 accelerated_generator_->set_frame(nullptr); | 320 // SkImage and the underlying texture can be delete. |
| 321 // TODO(dcastagna): release the texture in a callback once Skia API exposes | |
|
bsalomon
2015/05/29 14:49:26
Why don't we go ahead and add this functionality t
Daniele Castagna
2015/06/05 04:15:31
With the last patch texture_id is kept around for
| |
| 322 // the functionality. | |
| 323 if (texture_id) { | |
| 324 DCHECK(!IsCanvasDrawingOnPicture(canvas)); | |
| 325 DCHECK(context_3d.gl); | |
| 326 context_3d.gl->DeleteTextures(1, &texture_id); | |
| 327 } | |
| 431 } | 328 } |
| 432 | 329 |
| 433 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 330 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
| 434 SkCanvas* canvas, | 331 SkCanvas* canvas, |
| 435 const Context3D& context_3d) { | 332 const Context3D& context_3d) { |
| 436 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, | 333 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, |
| 437 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); | 334 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); |
| 438 } | 335 } |
| 439 | 336 |
| 440 // static | 337 // static |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); | 504 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); |
| 608 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); | 505 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); |
| 609 | 506 |
| 610 gl->DeleteTextures(1, &source_texture); | 507 gl->DeleteTextures(1, &source_texture); |
| 611 gl->Flush(); | 508 gl->Flush(); |
| 612 | 509 |
| 613 SyncPointClientImpl client(gl); | 510 SyncPointClientImpl client(gl); |
| 614 video_frame->UpdateReleaseSyncPoint(&client); | 511 video_frame->UpdateReleaseSyncPoint(&client); |
| 615 } | 512 } |
| 616 | 513 |
| 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 | 514 } // namespace media |
| OLD | NEW |