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

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

Issue 1144323003: media: Refactor SkCanvasVideoRenderer to use SkImages and not SkBitmaps. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase on master. Re-add the cache. Created 5 years, 6 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/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 "ui/gfx/skbitmap_operations.h"
20 19
21 // Skia internal format depends on a platform. On Android it is ABGR, on others 20 // Skia internal format depends on a platform. On Android it is ABGR, on others
22 // it is ARGB. 21 // it is ARGB.
23 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ 22 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
24 SK_A32_SHIFT == 24 23 SK_A32_SHIFT == 24
25 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB 24 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
26 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB 25 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
27 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ 26 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
28 SK_A32_SHIFT == 24 27 SK_A32_SHIFT == 24
29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR 28 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR 29 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
31 #else 30 #else
32 #error Unexpected Skia ARGB_8888 layout! 31 #error Unexpected Skia ARGB_8888 layout!
33 #endif 32 #endif
34 33
35 namespace media { 34 namespace media {
36 35
37 namespace { 36 namespace {
38 37
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;
44
45 bool CheckColorSpace(const scoped_refptr<VideoFrame>& video_frame, 38 bool CheckColorSpace(const scoped_refptr<VideoFrame>& video_frame,
46 VideoFrame::ColorSpace color_space) { 39 VideoFrame::ColorSpace color_space) {
47 int result; 40 int result;
48 return video_frame->metadata()->GetInteger( 41 return video_frame->metadata()->GetInteger(
49 media::VideoFrameMetadata::COLOR_SPACE, &result) && 42 media::VideoFrameMetadata::COLOR_SPACE, &result) &&
50 result == color_space; 43 result == color_space;
51 } 44 }
52 45
53 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap,
54 const gfx::Size& size) {
55 return bitmap->getTexture() && bitmap->width() == size.width() &&
56 bitmap->height() == size.height();
57 }
58
59 bool AllocateSkBitmapTexture(GrContext* gr,
60 SkBitmap* bitmap,
61 const gfx::Size& size) {
62 DCHECK(gr);
63 GrTextureDesc desc;
64 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid
65 // RGBA to BGRA conversion.
66 desc.fConfig = kRGBA_8888_GrPixelConfig;
67 desc.fFlags = kRenderTarget_GrSurfaceFlag;
68 desc.fSampleCnt = 0;
69 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
70 desc.fWidth = size.width();
71 desc.fHeight = size.height();
72 skia::RefPtr<GrTexture> texture = skia::AdoptRef(
73 gr->textureProvider()->refScratchTexture(
74 desc, GrTextureProvider::kExact_ScratchTexMatch));
75 if (!texture.get())
76 return false;
77
78 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
79 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
80 if (!pixel_ref)
81 return false;
82 bitmap->setInfo(info);
83 bitmap->setPixelRef(pixel_ref)->unref();
84 return true;
85 }
86
87 bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame,
88 SkBitmap* bitmap,
89 const Context3D& context_3d) {
90 // Check if we could reuse existing texture based bitmap.
91 // Otherwise, release existing texture based bitmap and allocate
92 // a new one based on video size.
93 if (!IsSkBitmapProperlySizedTexture(bitmap,
94 video_frame->visible_rect().size())) {
95 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap,
96 video_frame->visible_rect().size())) {
97 return false;
98 }
99 }
100
101 unsigned texture_id =
102 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
103 // If CopyVideoFrameTextureToGLTexture() changes the state of the
104 // |texture_id|, it's needed to invalidate the state cached in skia,
105 // but currently the state isn't changed.
106 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
107 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true,
108 false);
109 bitmap->notifyPixelsChanged();
110 return true;
111 }
112
113 class SyncPointClientImpl : public VideoFrame::SyncPointClient { 46 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
114 public: 47 public:
115 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} 48 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
116 ~SyncPointClientImpl() override {} 49 ~SyncPointClientImpl() override {}
117 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } 50 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
118 void WaitSyncPoint(uint32 sync_point) override { 51 void WaitSyncPoint(uint32 sync_point) override {
119 gl_->WaitSyncPointCHROMIUM(sync_point); 52 gl_->WaitSyncPointCHROMIUM(sync_point);
120 } 53 }
121 54
122 private: 55 private:
123 gpu::gles2::GLES2Interface* gl_; 56 gpu::gles2::GLES2Interface* gl_;
124 57
125 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); 58 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
126 }; 59 };
127 60
61 // Creates a SkImage from a |video_frame| backed by native resources.
62 // The SkImage will not take ownership of the underlying resources and the
63 // caller will have to delete them after the SkImage is used.
64 // |source_textures| is a pointer to an array that will be filled with
65 // texture ids backing the returned image.
66 skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
67 const scoped_refptr<VideoFrame>& video_frame,
68 const Context3D& context_3d,
69 unsigned* source_textures) {
70 // TODO(dcastagna): Add support for YUV420.
71 DCHECK_EQ(VideoFrame::ARGB, video_frame->format());
72
73 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
74 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
75 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
76 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
77 << mailbox_holder.texture_target;
78
79 gpu::gles2::GLES2Interface* gl = context_3d.gl;
80 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
81 // TODO(dcastagna): At the moment Skia doesn't support targets different
82 // than GL_TEXTURE_2D. Avoid this copy once
83 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
84 gl->GenTextures(1, source_textures);
85 DCHECK(*source_textures);
86 gl->BindTexture(GL_TEXTURE_2D, *source_textures);
87 SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
88 gl, video_frame.get(), *source_textures, GL_RGBA, GL_UNSIGNED_BYTE,
89 true, false);
90 } else {
91 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
92 *source_textures = gl->CreateAndConsumeTextureCHROMIUM(
93 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
dshwang 2015/06/05 18:58:16 Following two lines is needed to insert sync point
dshwang 2015/06/05 19:08:41 ah, I found you insert sync point at the end of dr
dshwang 2015/06/08 12:21:43 In this case, this class should not cache the text
Daniele Castagna 2015/06/09 23:21:11 The lifetime of the texture id is currently not we
dshwang 2015/06/10 07:17:39 I guess final solution would be to not cache. why
94 }
95 GrBackendTextureDesc desc;
96 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
97 desc.fWidth = video_frame->coded_size().width();
98 desc.fHeight = video_frame->coded_size().height();
99 desc.fConfig = kRGBA_8888_GrPixelConfig;
100 desc.fTextureHandle = *source_textures;
101 return skia::AdoptRef(SkImage::NewFromTexture(context_3d.gr_context, desc));
102 }
103
128 } // anonymous namespace 104 } // anonymous namespace
129 105
130 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. 106 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
131 class VideoImageGenerator : public SkImageGenerator { 107 class VideoImageGenerator : public SkImageGenerator {
132 public: 108 public:
133 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) 109 VideoImageGenerator(VideoFrame* frame)
134 : SkImageGenerator( 110 : SkImageGenerator(
135 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), 111 SkImageInfo::MakeN32Premul(frame->visible_rect().width(),
136 frame->visible_rect().height())) 112 frame->visible_rect().height())),
137 , frame_(frame) { 113 frame_(frame) {}
138 DCHECK(frame_.get());
139 }
140 ~VideoImageGenerator() override {} 114 ~VideoImageGenerator() override {}
141 115
142 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } 116 void set_frame(VideoFrame* frame) { frame_ = frame; }
143 117
144 protected: 118 protected:
145 Result onGetPixels(const SkImageInfo& info, 119 Result onGetPixels(const SkImageInfo& info,
146 void* pixels, 120 void* pixels,
147 size_t row_bytes, 121 size_t row_bytes,
148 SkPMColor ctable[], 122 SkPMColor ctable[],
149 int* ctable_count) override { 123 int* ctable_count) override {
150 if (!frame_.get()) 124 if (!frame_)
151 return kInvalidInput; 125 return kInvalidInput;
152 // If skia couldn't do the YUV conversion on GPU, we will on CPU. 126 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
153 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( 127 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
154 frame_, pixels, row_bytes); 128 frame_, pixels, row_bytes);
155 return kSuccess; 129 return kSuccess;
156 } 130 }
157 131
158 bool onGetYUV8Planes(SkISize sizes[3], 132 bool onGetYUV8Planes(SkISize sizes[3],
159 void* planes[3], 133 void* planes[3],
160 size_t row_bytes[3], 134 size_t row_bytes[3],
161 SkYUVColorSpace* color_space) override { 135 SkYUVColorSpace* color_space) override {
162 if (!frame_.get() || !media::VideoFrame::IsYuvPlanar(frame_->format()) || 136 if (!frame_ || !media::VideoFrame::IsYuvPlanar(frame_->format()) ||
163 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion, 137 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion,
164 // or YUVA conversion. Remove this case once it does. As-is we will 138 // or YUVA conversion. Remove this case once it does. As-is we will
165 // fall back on the pure-software path in this case. 139 // fall back on the pure-software path in this case.
166 CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_HD_REC709) || 140 CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_HD_REC709) ||
167 frame_->format() == VideoFrame::YV12A) { 141 frame_->format() == VideoFrame::YV12A) {
168 return false; 142 return false;
169 } 143 }
170 144
171 if (color_space) { 145 if (color_space) {
172 if (CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_JPEG)) 146 if (CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_JPEG))
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 in_line += in_line_stride; 192 in_line += in_line_stride;
219 out_line += out_line_stride; 193 out_line += out_line_stride;
220 } 194 }
221 } 195 }
222 } 196 }
223 } 197 }
224 return true; 198 return true;
225 } 199 }
226 200
227 private: 201 private:
228 scoped_refptr<VideoFrame> frame_; 202 VideoFrame* frame_;
229 203
230 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); 204 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
231 }; 205 };
232 206
233 SkCanvasVideoRenderer::SkCanvasVideoRenderer() 207 SkCanvasVideoRenderer::SkCanvasVideoRenderer() {
234 : last_frame_timestamp_(media::kNoTimestamp()),
235 frame_deleting_timer_(
dshwang 2015/06/05 19:08:41 I think it's needed. e.g. if some canvas draws vid
Daniele Castagna 2015/06/05 22:05:32 SkImage caches the result internally and I'd assum
dshwang 2015/06/08 12:21:43 3 second timer was introduced to eagerly remove ca
Daniele Castagna 2015/06/09 23:21:11 My rationale for removing the delaytimer is that n
dshwang 2015/06/10 07:17:39 How will you remove cache for software path?
236 FROM_HERE,
237 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
238 this,
239 &SkCanvasVideoRenderer::ResetLastFrame),
240 accelerated_generator_(nullptr),
241 accelerated_last_frame_timestamp_(media::kNoTimestamp()),
242 accelerated_frame_deleting_timer_(
243 FROM_HERE,
244 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
245 this,
246 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame) {
247 last_frame_.setIsVolatile(true);
248 } 208 }
249 209
250 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} 210 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {
211 ResetCache();
212 }
251 213
252 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, 214 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
253 SkCanvas* canvas, 215 SkCanvas* canvas,
254 const gfx::RectF& dest_rect, 216 const gfx::RectF& dest_rect,
255 uint8 alpha, 217 uint8 alpha,
256 SkXfermode::Mode mode, 218 SkXfermode::Mode mode,
257 VideoRotation video_rotation, 219 VideoRotation video_rotation,
258 const Context3D& context_3d) { 220 const Context3D& context_3d) {
259 if (alpha == 0) { 221 if (alpha == 0) {
260 return; 222 return;
261 } 223 }
262 224
263 SkRect dest; 225 SkRect dest;
264 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); 226 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
265 227
266 SkPaint paint; 228 SkPaint paint;
267 paint.setAlpha(alpha); 229 paint.setAlpha(alpha);
268 230
269 // Paint black rectangle if there isn't a frame available or the 231 // Paint black rectangle if there isn't a frame available or the
270 // frame has an unexpected format. 232 // frame has an unexpected format.
271 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || 233 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
272 !(media::VideoFrame::IsYuvPlanar(video_frame->format()) || 234 !(media::VideoFrame::IsYuvPlanar(video_frame->format()) ||
273 (video_frame->storage_type() == media::VideoFrame::STORAGE_TEXTURE))) { 235 (video_frame->storage_type() == media::VideoFrame::STORAGE_TEXTURE))) {
274 canvas->drawRect(dest, paint); 236 canvas->drawRect(dest, paint);
275 canvas->flush(); 237 canvas->flush();
276 return; 238 return;
277 } 239 }
278 240
279 SkBitmap* target_frame = nullptr; 241 gpu::gles2::GLES2Interface* gl = context_3d.gl;
280 242
281 if (video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE) { 243 // This might be wrong, two different videos could be drawn to the same
282 // Draw HW Video on both SW and HW Canvas. 244 // canvas and the two different videoframes could have the same timestamp.
283 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. 245 if (last_image_ && video_frame->timestamp() == last_timestamp_) {
284 if (accelerated_last_frame_.isNull() || 246 // |last_image_| can be reused.
285 video_frame->timestamp() != accelerated_last_frame_timestamp_) { 247 // |video_generator_| will be set only if the last cache videoframe was
286 DCHECK(context_3d.gl); 248 // a software videoframe.
249 if (video_generator_)
250 video_generator_->set_frame(video_frame.get());
251 } else {
252 ResetCache();
253 // Generate a new image.
254 if (video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE) {
287 DCHECK(context_3d.gr_context); 255 DCHECK(context_3d.gr_context);
288 if (accelerated_generator_) { 256 DCHECK(gl);
289 // Reset SkBitmap used in SWVideo-to-HWCanvas path. 257 last_image_ = NewSkImageFromVideoFrameNative(video_frame, context_3d,
290 accelerated_last_frame_.reset(); 258 &last_texture_id_);
291 accelerated_generator_ = nullptr; 259 last_gl_ = gl;
292 } 260 } else {
293 if (!CopyVideoFrameTextureToSkBitmapTexture( 261 video_generator_ = new VideoImageGenerator(video_frame.get());
294 video_frame.get(), &accelerated_last_frame_, context_3d)) { 262 last_image_ = skia::AdoptRef(SkImage::NewFromGenerator(video_generator_));
295 NOTREACHED();
296 return;
297 }
298 DCHECK(video_frame->visible_rect().width() ==
299 accelerated_last_frame_.width() &&
300 video_frame->visible_rect().height() ==
301 accelerated_last_frame_.height());
302
303 accelerated_last_frame_timestamp_ = video_frame->timestamp();
304 } 263 }
305 target_frame = &accelerated_last_frame_; 264 last_timestamp_ = video_frame->timestamp();
306 accelerated_frame_deleting_timer_.Reset();
307 } else if (canvas->getGrContext()) {
308 if (accelerated_last_frame_.isNull() ||
309 video_frame->timestamp() != accelerated_last_frame_timestamp_) {
310 // Draw SW Video on HW Canvas.
311 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) {
312 // Reset SkBitmap used in HWVideo-to-HWCanvas path.
313 accelerated_last_frame_.reset();
314 }
315 accelerated_generator_ = new VideoImageGenerator(video_frame);
316
317 // Note: This takes ownership of |accelerated_generator_|.
318 if (!SkInstallDiscardablePixelRef(accelerated_generator_,
319 &accelerated_last_frame_)) {
320 NOTREACHED();
321 return;
322 }
323 DCHECK(video_frame->visible_rect().width() ==
324 accelerated_last_frame_.width() &&
325 video_frame->visible_rect().height() ==
326 accelerated_last_frame_.height());
327
328 accelerated_last_frame_timestamp_ = video_frame->timestamp();
329 } else if (accelerated_generator_) {
330 accelerated_generator_->set_frame(video_frame);
331 }
332 target_frame = &accelerated_last_frame_;
333 accelerated_frame_deleting_timer_.Reset();
334 } else {
335 // Draw SW Video on SW Canvas.
336 DCHECK(VideoFrame::IsMappable(video_frame->storage_type()));
337 if (last_frame_.isNull() ||
338 video_frame->timestamp() != last_frame_timestamp_) {
339 // Check if |bitmap| needs to be (re)allocated.
340 if (last_frame_.isNull() ||
341 last_frame_.width() != video_frame->visible_rect().width() ||
342 last_frame_.height() != video_frame->visible_rect().height()) {
343 last_frame_.allocN32Pixels(video_frame->visible_rect().width(),
344 video_frame->visible_rect().height());
345 last_frame_.setIsVolatile(true);
346 }
347 last_frame_.lockPixels();
348 ConvertVideoFrameToRGBPixels(
349 video_frame, last_frame_.getPixels(), last_frame_.rowBytes());
dshwang 2015/06/08 12:21:43 does VideoGenerator way have same performance to c
350 last_frame_.notifyPixelsChanged();
351 last_frame_.unlockPixels();
352 last_frame_timestamp_ = video_frame->timestamp();
353 }
354 target_frame = &last_frame_;
355 frame_deleting_timer_.Reset();
356 } 265 }
357 266
358 paint.setXfermodeMode(mode); 267 paint.setXfermodeMode(mode);
359 paint.setFilterQuality(kLow_SkFilterQuality); 268 paint.setFilterQuality(kLow_SkFilterQuality);
360 269
361 bool need_transform = 270 bool need_transform =
362 video_rotation != VIDEO_ROTATION_0 || 271 video_rotation != VIDEO_ROTATION_0 ||
363 dest_rect.size() != video_frame->visible_rect().size() || 272 dest_rect.size() != video_frame->visible_rect().size() ||
364 !dest_rect.origin().IsOrigin(); 273 !dest_rect.origin().IsOrigin();
365 if (need_transform) { 274 if (need_transform) {
(...skipping 17 matching lines...) Expand all
383 } 292 }
384 canvas->rotate(angle); 293 canvas->rotate(angle);
385 294
386 gfx::SizeF rotated_dest_size = dest_rect.size(); 295 gfx::SizeF rotated_dest_size = dest_rect.size();
387 if (video_rotation == VIDEO_ROTATION_90 || 296 if (video_rotation == VIDEO_ROTATION_90 ||
388 video_rotation == VIDEO_ROTATION_270) { 297 video_rotation == VIDEO_ROTATION_270) {
389 rotated_dest_size = 298 rotated_dest_size =
390 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); 299 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
391 } 300 }
392 canvas->scale( 301 canvas->scale(
393 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), 302 SkFloatToScalar(rotated_dest_size.width() / last_image_->width()),
394 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); 303 SkFloatToScalar(rotated_dest_size.height() / last_image_->height()));
395 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), 304 canvas->translate(-SkFloatToScalar(last_image_->width() * 0.5f),
396 -SkFloatToScalar(target_frame->height() * 0.5f)); 305 -SkFloatToScalar(last_image_->height() * 0.5f));
397 } 306 }
398 canvas->drawBitmap(*target_frame, 0, 0, &paint); 307
308 canvas->drawImage(last_image_.get(), 0, 0, &paint);
399 if (need_transform) 309 if (need_transform)
400 canvas->restore(); 310 canvas->restore();
311 // Make sure to flush so we can remove the videoframe from the generator.
401 canvas->flush(); 312 canvas->flush();
402 // SkCanvas::flush() causes the generator to generate SkImage, so delete 313
403 // |video_frame| not to be outlived. 314 if (last_texture_id_) {
404 if (canvas->getGrContext() && accelerated_generator_) 315 SyncPointClientImpl client(gl);
405 accelerated_generator_->set_frame(nullptr); 316 // Make sure the video_frame can go back to the pool after the native
317 // texture has been used for drawing.
318 video_frame->UpdateReleaseSyncPoint(&client);
dshwang 2015/06/08 12:21:43 It's needed only for GL_TEXTURE_2D case.
Daniele Castagna 2015/06/09 23:21:11 That's true, but considering that eventually it wi
dshwang 2015/06/10 07:17:39 Acknowledged.
319 }
320
321 // TODO(dcastagna): here we're assuming |video_generator_| will still be valid
322 // after SkImage::NewFromGenerator took the ownership.
323 // Fix this once https://code.google.com/p/skia/issues/detail?id=3870 is
324 // addressed.
325 if (video_generator_)
326 video_generator_->set_frame(nullptr);
406 } 327 }
407 328
408 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, 329 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
409 SkCanvas* canvas, 330 SkCanvas* canvas,
410 const Context3D& context_3d) { 331 const Context3D& context_3d) {
411 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, 332 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff,
412 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); 333 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d);
413 } 334 }
414 335
415 // static 336 // static
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 unsigned int type, 477 unsigned int type,
557 bool premultiply_alpha, 478 bool premultiply_alpha,
558 bool flip_y) { 479 bool flip_y) {
559 DCHECK(video_frame); 480 DCHECK(video_frame);
560 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE); 481 DCHECK_EQ(video_frame->storage_type(), VideoFrame::STORAGE_TEXTURE);
561 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); 482 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format()));
562 483
563 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 484 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
564 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 485 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
565 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 486 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
566 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES); 487 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
488 << mailbox_holder.texture_target;
567 489
568 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); 490 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
569 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 491 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
570 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 492 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
571 493
572 // The video is stored in a unmultiplied format, so premultiply 494 // The video is stored in a unmultiplied format, so premultiply
573 // if necessary. 495 // if necessary.
574 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha); 496 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha);
575 // Application itself needs to take care of setting the right |flip_y| 497 // Application itself needs to take care of setting the right |flip_y|
576 // value down to get the expected result. 498 // value down to get the expected result.
577 // "flip_y == true" means to reverse the video orientation while 499 // "flip_y == true" means to reverse the video orientation while
578 // "flip_y == false" means to keep the intrinsic orientation. 500 // "flip_y == false" means to keep the intrinsic orientation.
579 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y); 501 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
580 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture, 502 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture,
581 internal_format, type); 503 internal_format, type);
582 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false); 504 gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
583 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); 505 gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
584 506
585 gl->DeleteTextures(1, &source_texture); 507 gl->DeleteTextures(1, &source_texture);
586 gl->Flush(); 508 gl->Flush();
587 509
588 SyncPointClientImpl client(gl); 510 SyncPointClientImpl client(gl);
589 video_frame->UpdateReleaseSyncPoint(&client); 511 video_frame->UpdateReleaseSyncPoint(&client);
590 } 512 }
591 513
592 void SkCanvasVideoRenderer::ResetLastFrame() { 514 void SkCanvasVideoRenderer::ResetCache() {
593 last_frame_.reset(); 515 // Clear cached values.
594 last_frame_timestamp_ = media::kNoTimestamp(); 516 video_generator_ = nullptr;
595 } 517 last_image_ = nullptr;
596 518 last_timestamp_ = kNoTimestamp();
597 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { 519 if (last_texture_id_) {
598 accelerated_last_frame_.reset(); 520 DCHECK(last_gl_);
599 accelerated_generator_ = nullptr; 521 last_gl_->DeleteTextures(1, &last_texture_id_);
600 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); 522 last_texture_id_ = 0;
523 }
601 } 524 }
602 525
603 } // namespace media 526 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698