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

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: Clear the cache after 3 seconds. Created 5 years, 5 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
« no previous file with comments | « media/blink/skcanvas_video_renderer.h ('k') | media/blink/skcanvas_video_renderer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/SkImage.h"
16 #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" 17 #include "third_party/skia/include/gpu/GrContext.h"
18 #include "third_party/skia/include/gpu/GrPaint.h" 18 #include "third_party/skia/include/gpu/GrPaint.h"
19 #include "third_party/skia/include/gpu/GrTexture.h" 19 #include "third_party/skia/include/gpu/GrTexture.h"
20 #include "third_party/skia/include/gpu/GrTextureProvider.h" 20 #include "third_party/skia/include/gpu/GrTextureProvider.h"
21 #include "third_party/skia/include/gpu/SkGr.h"
22 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
23 #include "ui/gfx/skbitmap_operations.h"
24 21
25 // Skia internal format depends on a platform. On Android it is ABGR, on others 22 // Skia internal format depends on a platform. On Android it is ABGR, on others
26 // it is ARGB. 23 // it is ARGB.
27 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ 24 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
28 SK_A32_SHIFT == 24 25 SK_A32_SHIFT == 24
29 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB 26 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
30 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB 27 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
31 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ 28 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
32 SK_A32_SHIFT == 24 29 SK_A32_SHIFT == 24
33 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR 30 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
34 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR 31 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
35 #else 32 #else
36 #error Unexpected Skia ARGB_8888 layout! 33 #error Unexpected Skia ARGB_8888 layout!
37 #endif 34 #endif
38 35
39 namespace media { 36 namespace media {
40 37
41 namespace { 38 namespace {
42 39
43 // This class keeps two temporary resources; software bitmap, hardware bitmap. 40 // This class keeps the last image drawn.
44 // If both bitmap are created and then only software bitmap is updated every 41 // We delete the temporary resource if it is not used for 3 seconds.
45 // frame, hardware bitmap outlives until the media player dies. So we delete
46 // a temporary resource if it is not used for 3 sec.
47 const int kTemporaryResourceDeletionDelay = 3; // Seconds; 42 const int kTemporaryResourceDeletionDelay = 3; // Seconds;
48 43
49 bool CheckColorSpace(const scoped_refptr<VideoFrame>& video_frame, 44 bool CheckColorSpace(const scoped_refptr<VideoFrame>& video_frame,
50 VideoFrame::ColorSpace color_space) { 45 VideoFrame::ColorSpace color_space) {
51 int result; 46 int result;
52 return video_frame->metadata()->GetInteger( 47 return video_frame->metadata()->GetInteger(
53 VideoFrameMetadata::COLOR_SPACE, &result) && 48 VideoFrameMetadata::COLOR_SPACE, &result) &&
54 result == color_space; 49 result == color_space;
55 } 50 }
56 51
57 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap,
58 const gfx::Size& size) {
59 return bitmap->getTexture() && bitmap->width() == size.width() &&
60 bitmap->height() == size.height();
61 }
62
63 bool AllocateSkBitmapTexture(GrContext* gr,
64 SkBitmap* bitmap,
65 const gfx::Size& size) {
66 DCHECK(gr);
67 GrTextureDesc desc;
68 // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, to avoid
69 // RGBA to BGRA conversion.
70 desc.fConfig = kRGBA_8888_GrPixelConfig;
71 desc.fFlags = kRenderTarget_GrSurfaceFlag;
72 desc.fSampleCnt = 0;
73 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
74 desc.fWidth = size.width();
75 desc.fHeight = size.height();
76 skia::RefPtr<GrTexture> texture = skia::AdoptRef(
77 gr->textureProvider()->refScratchTexture(
78 desc, GrTextureProvider::kExact_ScratchTexMatch));
79 if (!texture.get())
80 return false;
81
82 SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
83 SkGrPixelRef* pixel_ref = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
84 if (!pixel_ref)
85 return false;
86 bitmap->setInfo(info);
87 bitmap->setPixelRef(pixel_ref)->unref();
88 return true;
89 }
90
91 class SyncPointClientImpl : public VideoFrame::SyncPointClient { 52 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
92 public: 53 public:
93 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} 54 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
94 ~SyncPointClientImpl() override {} 55 ~SyncPointClientImpl() override {}
95 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } 56 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
96 void WaitSyncPoint(uint32 sync_point) override { 57 void WaitSyncPoint(uint32 sync_point) override {
97 gl_->WaitSyncPointCHROMIUM(sync_point); 58 gl_->WaitSyncPointCHROMIUM(sync_point);
98 } 59 }
99 60
100 private: 61 private:
101 gpu::gles2::GLES2Interface* gl_; 62 gpu::gles2::GLES2Interface* gl_;
102 63
103 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); 64 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
104 }; 65 };
105 66
106 scoped_ptr<SkImage> CreateSkImageFromVideoFrameYUVTextures( 67 skia::RefPtr<SkImage> NewSkImageFromVideoFrameYUVTextures(
107 VideoFrame* video_frame, 68 const scoped_refptr<VideoFrame>& video_frame,
108 const Context3D& context_3d) { 69 const Context3D& context_3d) {
109 // Support only TEXTURE_YUV_420. 70 // Support only TEXTURE_YUV_420.
110 DCHECK(video_frame->HasTextures()); 71 DCHECK(video_frame->HasTextures());
111 DCHECK_EQ(media::VideoFrame::I420, video_frame->format()); 72 DCHECK_EQ(media::VideoFrame::I420, video_frame->format());
112 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format())); 73 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format()));
113 74
114 gpu::gles2::GLES2Interface* gl = context_3d.gl; 75 gpu::gles2::GLES2Interface* gl = context_3d.gl;
115 DCHECK(gl); 76 DCHECK(gl);
116 gfx::Size ya_tex_size = video_frame->coded_size(); 77 gfx::Size ya_tex_size = video_frame->coded_size();
117 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2, 78 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
(...skipping 26 matching lines...) Expand all
144 if (CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_JPEG)) 105 if (CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_JPEG))
145 color_space = kJPEG_SkYUVColorSpace; 106 color_space = kJPEG_SkYUVColorSpace;
146 107
147 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context, 108 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context,
148 color_space, handles, yuvSizes, 109 color_space, handles, yuvSizes,
149 kTopLeft_GrSurfaceOrigin); 110 kTopLeft_GrSurfaceOrigin);
150 DCHECK(img); 111 DCHECK(img);
151 gl->DeleteTextures(3, source_textures); 112 gl->DeleteTextures(3, source_textures);
152 SyncPointClientImpl client(gl); 113 SyncPointClientImpl client(gl);
153 video_frame->UpdateReleaseSyncPoint(&client); 114 video_frame->UpdateReleaseSyncPoint(&client);
154 return make_scoped_ptr(img); 115 return skia::AdoptRef(img);
155 } 116 }
156 117
157 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, 118 // Creates a SkImage from a |video_frame| backed by native resources.
158 SkBitmap* bitmap, 119 // The SkImage will take ownership of the underlying resource.
159 const Context3D& context_3d) { 120 skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
160 // Check if we could reuse existing texture based bitmap. 121 const scoped_refptr<VideoFrame>& video_frame,
161 // Otherwise, release existing texture based bitmap and allocate 122 const Context3D& context_3d) {
162 // a new one based on video size. 123 DCHECK_EQ(VideoFrame::ARGB, video_frame->format());
163 if (!IsSkBitmapProperlySizedTexture(bitmap, 124
164 video_frame->visible_rect().size())) { 125 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
165 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, 126 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
166 video_frame->visible_rect().size())) { 127 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
167 return false; 128 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
168 } 129 << mailbox_holder.texture_target;
130
131 gpu::gles2::GLES2Interface* gl = context_3d.gl;
132 unsigned source_texture = 0;
133 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
134 // TODO(dcastagna): At the moment Skia doesn't support targets different
135 // than GL_TEXTURE_2D. Avoid this copy once
136 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
137 gl->GenTextures(1, &source_texture);
138 DCHECK(source_texture);
139 gl->BindTexture(GL_TEXTURE_2D, source_texture);
140 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
141 gl, video_frame.get(), source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true,
142 false);
143 } else {
144 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
145 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
146 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
dshwang 2015/07/15 15:10:52 This code bind the texture of the mailbox and then
Daniele Castagna 2015/07/17 15:42:41 The texture will be deleted after both SkImage and
dshwang 2015/07/20 10:47:47 let me imagine one worse senario. There are two ac
Daniele Castagna 2015/07/30 19:55:00 GVD waits for release_sync_point_ in VideoFrame be
dshwang 2015/08/03 17:51:52 That's problem. While GVD waits for |release_sync_
Daniele Castagna 2015/08/03 20:52:21 This wouldn't be a problem since last_image_ is no
169 } 147 }
170 148 GrBackendTextureDesc desc;
171 unsigned texture_id = 149 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
172 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); 150 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
173 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the 151 desc.fWidth = video_frame->coded_size().width();
174 // |texture_id|, it's needed to invalidate the state cached in skia, 152 desc.fHeight = video_frame->coded_size().height();
175 // but currently the state isn't changed. 153 desc.fConfig = kRGBA_8888_GrPixelConfig;
176 154 desc.fTextureHandle = source_texture;
177 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 155 return skia::AdoptRef(
178 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, 156 SkImage::NewFromAdoptedTexture(context_3d.gr_context, desc));
179 false);
180 bitmap->notifyPixelsChanged();
181 return true;
182 } 157 }
183 158
184 } // anonymous namespace 159 } // anonymous namespace
185 160
186 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. 161 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
187 class VideoImageGenerator : public SkImageGenerator { 162 class VideoImageGenerator : public SkImageGenerator {
188 public: 163 public:
189 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) 164 VideoImageGenerator(VideoFrame* frame)
190 : SkImageGenerator( 165 : SkImageGenerator(
191 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), 166 SkImageInfo::MakeN32Premul(frame->visible_rect().width(),
192 frame->visible_rect().height())) 167 frame->visible_rect().height())),
193 , frame_(frame) { 168 frame_(frame) {}
194 DCHECK(frame_.get());
195 }
196 ~VideoImageGenerator() override {} 169 ~VideoImageGenerator() override {}
197 170
198 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } 171 void set_frame(VideoFrame* frame) { frame_ = frame; }
199 172
200 protected: 173 protected:
201 Result onGetPixels(const SkImageInfo& info, 174 Result onGetPixels(const SkImageInfo& info,
202 void* pixels, 175 void* pixels,
203 size_t row_bytes, 176 size_t row_bytes,
204 const Options&, 177 const Options&,
205 SkPMColor ctable[], 178 SkPMColor ctable[],
206 int* ctable_count) override { 179 int* ctable_count) override {
207 if (!frame_.get()) 180 if (!frame_)
208 return kInvalidInput; 181 return kInvalidInput;
209 // If skia couldn't do the YUV conversion on GPU, we will on CPU. 182 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
210 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( 183 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
211 frame_, pixels, row_bytes); 184 frame_, pixels, row_bytes);
212 return kSuccess; 185 return kSuccess;
213 } 186 }
214 187
215 bool onGetYUV8Planes(SkISize sizes[3], 188 bool onGetYUV8Planes(SkISize sizes[3],
216 void* planes[3], 189 void* planes[3],
217 size_t row_bytes[3], 190 size_t row_bytes[3],
218 SkYUVColorSpace* color_space) override { 191 SkYUVColorSpace* color_space) override {
219 if (!frame_.get() || !VideoFrame::IsYuvPlanar(frame_->format()) || 192 if (!frame_ || !media::VideoFrame::IsYuvPlanar(frame_->format()) ||
220 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion, 193 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion,
221 // or YUVA conversion. Remove this case once it does. As-is we will 194 // or YUVA conversion. Remove this case once it does. As-is we will
222 // fall back on the pure-software path in this case. 195 // fall back on the pure-software path in this case.
223 CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_HD_REC709) || 196 CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_HD_REC709) ||
224 frame_->format() == VideoFrame::YV12A) { 197 frame_->format() == VideoFrame::YV12A) {
225 return false; 198 return false;
226 } 199 }
227 200
228 if (color_space) { 201 if (color_space) {
229 if (CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_JPEG)) 202 if (CheckColorSpace(frame_, VideoFrame::COLOR_SPACE_JPEG))
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 in_line += in_line_stride; 246 in_line += in_line_stride;
274 out_line += out_line_stride; 247 out_line += out_line_stride;
275 } 248 }
276 } 249 }
277 } 250 }
278 } 251 }
279 return true; 252 return true;
280 } 253 }
281 254
282 private: 255 private:
283 scoped_refptr<VideoFrame> frame_; 256 VideoFrame* frame_;
284 257
285 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); 258 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
286 }; 259 };
287 260
288 SkCanvasVideoRenderer::SkCanvasVideoRenderer() 261 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
289 : last_frame_timestamp_(media::kNoTimestamp()), 262 : last_image_deleting_timer_(
290 frame_deleting_timer_(
291 FROM_HERE, 263 FROM_HERE,
292 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay), 264 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
293 this, 265 this,
294 &SkCanvasVideoRenderer::ResetLastFrame), 266 &SkCanvasVideoRenderer::ResetCache) {
295 accelerated_generator_(nullptr),
296 accelerated_last_frame_timestamp_(media::kNoTimestamp()),
297 accelerated_frame_deleting_timer_(
298 FROM_HERE,
299 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
300 this,
301 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame) {
302 last_frame_.setIsVolatile(true);
303 } 267 }
304 268
305 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} 269 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {
270 ResetCache();
271 }
306 272
307 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, 273 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
308 SkCanvas* canvas, 274 SkCanvas* canvas,
309 const gfx::RectF& dest_rect, 275 const gfx::RectF& dest_rect,
310 uint8 alpha, 276 uint8 alpha,
311 SkXfermode::Mode mode, 277 SkXfermode::Mode mode,
312 VideoRotation video_rotation, 278 VideoRotation video_rotation,
313 const Context3D& context_3d) { 279 const Context3D& context_3d) {
314 if (alpha == 0) { 280 if (alpha == 0) {
315 return; 281 return;
316 } 282 }
317 283
318 SkRect dest; 284 SkRect dest;
319 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); 285 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
320 286
321 SkPaint paint; 287 SkPaint paint;
322 paint.setAlpha(alpha); 288 paint.setAlpha(alpha);
323 289
324 // Paint black rectangle if there isn't a frame available or the 290 // Paint black rectangle if there isn't a frame available or the
325 // frame has an unexpected format. 291 // frame has an unexpected format.
326 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || 292 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
327 !(VideoFrame::IsYuvPlanar(video_frame->format()) || 293 !(VideoFrame::IsYuvPlanar(video_frame->format()) ||
328 video_frame->HasTextures())) { 294 video_frame->HasTextures())) {
329 canvas->drawRect(dest, paint); 295 canvas->drawRect(dest, paint);
330 canvas->flush(); 296 canvas->flush();
331 return; 297 return;
332 } 298 }
333 299
334 SkBitmap* target_frame = nullptr; 300 gpu::gles2::GLES2Interface* gl = context_3d.gl;
335 301
336 if (video_frame->HasTextures()) { 302 // This might be wrong, two different videos could be drawn to the same
337 // Draw HW Video on both SW and HW Canvas. 303 // canvas and the two different videoframes could have the same timestamp.
338 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. 304 if (last_image_ && video_frame->timestamp() == last_timestamp_) {
339 if (accelerated_last_frame_.isNull() || 305 // |last_image_| can be reused.
340 video_frame->timestamp() != accelerated_last_frame_timestamp_) { 306 // |video_generator_| will be set only if the last cache videoframe was
341 DCHECK(context_3d.gl); 307 // a software videoframe.
308 if (video_generator_)
309 video_generator_->set_frame(video_frame.get());
310 } else {
311 ResetCache();
dshwang 2015/07/20 10:47:47 allocating texture or system memory is expensive.
Daniele Castagna 2015/07/30 19:54:59 Expensive compared to what? We used to reallocate
dshwang 2015/08/03 17:51:52 no, previously reuse cached SkBitmap without reall
Daniele Castagna 2015/08/03 20:52:21 Please refer to Brian's answer.
312 // Generate a new image.
313 if (video_frame->HasTextures()) {
342 DCHECK(context_3d.gr_context); 314 DCHECK(context_3d.gr_context);
343 if (accelerated_generator_) { 315 DCHECK(gl);
dshwang 2015/07/15 15:10:52 if |video_generator_| exists, delete |video_genera
Daniele Castagna 2015/07/17 15:42:41 ResetCache() above takes care of that.
dshwang 2015/07/20 10:47:47 I have question about ResetCache(). see above comm
344 // Reset SkBitmap used in SWVideo-to-HWCanvas path. 316 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) {
345 accelerated_last_frame_.reset(); 317 last_image_ = NewSkImageFromVideoFrameNative(video_frame, context_3d);
346 accelerated_generator_ = nullptr; 318 } else {
319 last_image_ =
320 NewSkImageFromVideoFrameYUVTextures(video_frame, context_3d);
347 } 321 }
348 322 SyncPointClientImpl client(gl);
349 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { 323 video_frame->UpdateReleaseSyncPoint(&client);
dshwang 2015/07/15 15:10:52 it's duplicated to same code in NewSkImageFromVide
Daniele Castagna 2015/07/17 15:42:41 Moved UpdateReleaseSyncPoint after we draw. I left
dshwang 2015/07/20 10:47:47 Acknowledged.
350 accelerated_last_image_.reset(); 324 } else {
351 if (!CopyVideoFrameSingleTextureToSkBitmap( 325 video_generator_ = new VideoImageGenerator(video_frame.get());
352 video_frame.get(), &accelerated_last_frame_, context_3d)) { 326 last_image_ = skia::AdoptRef(SkImage::NewFromGenerator(video_generator_));
dshwang 2015/07/15 15:10:52 now |last_image_| deal with both software SkCanvas
reed1 2015/07/15 15:37:32 It is. If there is a mismatch (e.g. raster-image t
dshwang 2015/07/15 16:21:10 thx for answering. in this case, gpu or raster ima
Daniele Castagna 2015/07/15 16:27:46 Is that a use case we care about? What's a real ex
dshwang 2015/07/15 16:37:13 here's real example, ./blink/tools/run_layout_test
dshwang 2015/07/15 17:56:24 It sounds good to this change. I agree on |last_im
353 NOTREACHED();
354 return;
355 }
356 DCHECK(video_frame->visible_rect().width() ==
357 accelerated_last_frame_.width() &&
358 video_frame->visible_rect().height() ==
359 accelerated_last_frame_.height());
360 } else {
361 accelerated_last_image_ = CreateSkImageFromVideoFrameYUVTextures(
362 video_frame.get(), context_3d);
363 DCHECK(accelerated_last_image_);
364 }
365 accelerated_last_frame_timestamp_ = video_frame->timestamp();
366 } 327 }
367 target_frame = &accelerated_last_frame_; 328 last_timestamp_ = video_frame->timestamp();
368 accelerated_frame_deleting_timer_.Reset();
369 } else if (canvas->getGrContext()) {
370 if (accelerated_last_frame_.isNull() ||
371 video_frame->timestamp() != accelerated_last_frame_timestamp_) {
372 // Draw SW Video on HW Canvas.
373 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) {
374 // Reset SkBitmap used in HWVideo-to-HWCanvas path.
375 accelerated_last_frame_.reset();
376 }
377 accelerated_generator_ = new VideoImageGenerator(video_frame);
378
379 // Note: This takes ownership of |accelerated_generator_|.
380 if (!SkInstallDiscardablePixelRef(accelerated_generator_,
381 &accelerated_last_frame_)) {
382 NOTREACHED();
383 return;
384 }
385 DCHECK(video_frame->visible_rect().width() ==
386 accelerated_last_frame_.width() &&
387 video_frame->visible_rect().height() ==
388 accelerated_last_frame_.height());
389
390 accelerated_last_frame_timestamp_ = video_frame->timestamp();
391 } else if (accelerated_generator_) {
392 accelerated_generator_->set_frame(video_frame);
393 }
394 target_frame = &accelerated_last_frame_;
395 accelerated_frame_deleting_timer_.Reset();
396 } else {
397 // Draw SW Video on SW Canvas.
398 DCHECK(video_frame->IsMappable());
399 if (last_frame_.isNull() ||
400 video_frame->timestamp() != last_frame_timestamp_) {
401 // Check if |bitmap| needs to be (re)allocated.
402 if (last_frame_.isNull() ||
403 last_frame_.width() != video_frame->visible_rect().width() ||
404 last_frame_.height() != video_frame->visible_rect().height()) {
405 last_frame_.allocN32Pixels(video_frame->visible_rect().width(),
406 video_frame->visible_rect().height());
407 last_frame_.setIsVolatile(true);
408 }
409 last_frame_.lockPixels();
410 ConvertVideoFrameToRGBPixels(
411 video_frame, last_frame_.getPixels(), last_frame_.rowBytes());
412 last_frame_.notifyPixelsChanged();
413 last_frame_.unlockPixels();
414 last_frame_timestamp_ = video_frame->timestamp();
415 }
416 target_frame = &last_frame_;
417 frame_deleting_timer_.Reset();
418 } 329 }
330 last_image_deleting_timer_.Reset();
419 331
420 paint.setXfermodeMode(mode); 332 paint.setXfermodeMode(mode);
421 paint.setFilterQuality(kLow_SkFilterQuality); 333 paint.setFilterQuality(kLow_SkFilterQuality);
422 334
423 const bool need_transform = 335 const bool need_transform =
424 video_rotation != VIDEO_ROTATION_0 || 336 video_rotation != VIDEO_ROTATION_0 ||
425 dest_rect.size() != video_frame->visible_rect().size() || 337 dest_rect.size() != video_frame->visible_rect().size() ||
426 !dest_rect.origin().IsOrigin(); 338 !dest_rect.origin().IsOrigin();
427 if (need_transform) { 339 if (need_transform) {
428 canvas->save(); 340 canvas->save();
(...skipping 16 matching lines...) Expand all
445 } 357 }
446 canvas->rotate(angle); 358 canvas->rotate(angle);
447 359
448 gfx::SizeF rotated_dest_size = dest_rect.size(); 360 gfx::SizeF rotated_dest_size = dest_rect.size();
449 if (video_rotation == VIDEO_ROTATION_90 || 361 if (video_rotation == VIDEO_ROTATION_90 ||
450 video_rotation == VIDEO_ROTATION_270) { 362 video_rotation == VIDEO_ROTATION_270) {
451 rotated_dest_size = 363 rotated_dest_size =
452 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); 364 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
453 } 365 }
454 canvas->scale( 366 canvas->scale(
455 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), 367 SkFloatToScalar(rotated_dest_size.width() / last_image_->width()),
456 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); 368 SkFloatToScalar(rotated_dest_size.height() / last_image_->height()));
457 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), 369 canvas->translate(-SkFloatToScalar(last_image_->width() * 0.5f),
458 -SkFloatToScalar(target_frame->height() * 0.5f)); 370 -SkFloatToScalar(last_image_->height() * 0.5f));
459 } 371 }
460 if (accelerated_last_image_) { 372 canvas->drawImage(last_image_.get(), 0, 0, &paint);
461 canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); 373
462 } else {
463 canvas->drawBitmap(*target_frame, 0, 0, &paint);
464 }
465 if (need_transform) 374 if (need_transform)
466 canvas->restore(); 375 canvas->restore();
376 // Make sure to flush so we can remove the videoframe from the generator.
467 canvas->flush(); 377 canvas->flush();
468 // SkCanvas::flush() causes the generator to generate SkImage, so delete 378 if (gl)
469 // |video_frame| not to be outlived. 379 gl->Flush();
dshwang 2015/07/15 15:10:52 Why is this glFlush needed?
Daniele Castagna 2015/07/17 15:42:41 Gone. I initially put it there to behave in the sa
470 if (canvas->getGrContext() && accelerated_generator_) 380
471 accelerated_generator_->set_frame(nullptr); 381 // TODO(dcastagna): here we're assuming |video_generator_| will still be valid
382 // after SkImage::NewFromGenerator took the ownership.
383 // Fix this once https://code.google.com/p/skia/issues/detail?id=3870 is
384 // addressed.
385 if (video_generator_)
386 video_generator_->set_frame(nullptr);
472 } 387 }
473 388
474 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, 389 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
475 SkCanvas* canvas, 390 SkCanvas* canvas,
476 const Context3D& context_3d) { 391 const Context3D& context_3d) {
477 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, 392 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff,
478 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); 393 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d);
479 } 394 }
480 395
481 // static 396 // static
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 unsigned int type, 537 unsigned int type,
623 bool premultiply_alpha, 538 bool premultiply_alpha,
624 bool flip_y) { 539 bool flip_y) {
625 DCHECK(video_frame); 540 DCHECK(video_frame);
626 DCHECK(video_frame->HasTextures()); 541 DCHECK(video_frame->HasTextures());
627 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); 542 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format()));
628 543
629 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 544 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
630 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 545 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
631 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 546 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
632 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES); 547 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
548 << mailbox_holder.texture_target;
633 549
634 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); 550 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
635 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 551 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
636 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 552 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
637 553
638 // The video is stored in a unmultiplied format, so premultiply 554 // The video is stored in a unmultiplied format, so premultiply
639 // if necessary. 555 // if necessary.
640 // Application itself needs to take care of setting the right |flip_y| 556 // Application itself needs to take care of setting the right |flip_y|
641 // value down to get the expected result. 557 // value down to get the expected result.
642 // "flip_y == true" means to reverse the video orientation while 558 // "flip_y == true" means to reverse the video orientation while
643 // "flip_y == false" means to keep the intrinsic orientation. 559 // "flip_y == false" means to keep the intrinsic orientation.
644 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture, 560 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture,
645 internal_format, type, 561 internal_format, type,
646 flip_y, premultiply_alpha, false); 562 flip_y, premultiply_alpha, false);
647 563
648 gl->DeleteTextures(1, &source_texture); 564 gl->DeleteTextures(1, &source_texture);
649 gl->Flush(); 565 gl->Flush();
650 566
651 SyncPointClientImpl client(gl); 567 SyncPointClientImpl client(gl);
652 video_frame->UpdateReleaseSyncPoint(&client); 568 video_frame->UpdateReleaseSyncPoint(&client);
653 } 569 }
654 570
655 void SkCanvasVideoRenderer::ResetLastFrame() { 571 void SkCanvasVideoRenderer::ResetCache() {
656 last_frame_.reset(); 572 // Clear cached values.
657 last_frame_timestamp_ = media::kNoTimestamp(); 573 video_generator_ = nullptr;
658 } 574 last_image_ = nullptr;
659 575 last_timestamp_ = kNoTimestamp();
660 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() {
661 accelerated_last_image_.reset();
662 accelerated_last_frame_.reset();
663 accelerated_generator_ = nullptr;
664 accelerated_last_frame_timestamp_ = media::kNoTimestamp();
665 } 576 }
666 577
667 } // namespace media 578 } // namespace media
OLDNEW
« no previous file with comments | « media/blink/skcanvas_video_renderer.h ('k') | media/blink/skcanvas_video_renderer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698