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

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: s/scoped_refptr<VideoFrame>&/VideoFrame*/ where possible. Created 5 years, 4 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 VideoFrame* video_frame, ColorSpace color_space) {
50 ColorSpace color_space) {
51 int result; 45 int result;
52 return video_frame->metadata()->GetInteger( 46 return video_frame->metadata()->GetInteger(
53 VideoFrameMetadata::COLOR_SPACE, &result) && 47 VideoFrameMetadata::COLOR_SPACE, &result) &&
54 result == color_space; 48 result == color_space;
55 } 49 }
56 50
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 { 51 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
92 public: 52 public:
93 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} 53 explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
94 ~SyncPointClientImpl() override {} 54 ~SyncPointClientImpl() override {}
95 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } 55 uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); }
96 void WaitSyncPoint(uint32 sync_point) override { 56 void WaitSyncPoint(uint32 sync_point) override {
97 gl_->WaitSyncPointCHROMIUM(sync_point); 57 gl_->WaitSyncPointCHROMIUM(sync_point);
98 } 58 }
99 59
100 private: 60 private:
101 gpu::gles2::GLES2Interface* gl_; 61 gpu::gles2::GLES2Interface* gl_;
102 62
103 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); 63 DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
104 }; 64 };
105 65
106 scoped_ptr<SkImage> CreateSkImageFromVideoFrameYUVTextures( 66 skia::RefPtr<SkImage> NewSkImageFromVideoFrameYUVTextures(
107 VideoFrame* video_frame, 67 const VideoFrame* video_frame,
108 const Context3D& context_3d) { 68 const Context3D& context_3d) {
109 // Support only TEXTURE_YUV_420. 69 // Support only TEXTURE_YUV_420.
110 DCHECK(video_frame->HasTextures()); 70 DCHECK(video_frame->HasTextures());
111 DCHECK_EQ(media::PIXEL_FORMAT_I420, video_frame->format()); 71 DCHECK_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
112 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format())); 72 DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format()));
113 73
114 gpu::gles2::GLES2Interface* gl = context_3d.gl; 74 gpu::gles2::GLES2Interface* gl = context_3d.gl;
115 DCHECK(gl); 75 DCHECK(gl);
116 gfx::Size ya_tex_size = video_frame->coded_size(); 76 gfx::Size ya_tex_size = video_frame->coded_size();
117 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2, 77 gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 if (CheckColorSpace(video_frame, media::COLOR_SPACE_JPEG)) 117 if (CheckColorSpace(video_frame, media::COLOR_SPACE_JPEG))
158 color_space = kJPEG_SkYUVColorSpace; 118 color_space = kJPEG_SkYUVColorSpace;
159 else if (CheckColorSpace(video_frame, media::COLOR_SPACE_HD_REC709)) 119 else if (CheckColorSpace(video_frame, media::COLOR_SPACE_HD_REC709))
160 color_space = kRec709_SkYUVColorSpace; 120 color_space = kRec709_SkYUVColorSpace;
161 121
162 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context, 122 SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context,
163 color_space, handles, yuvSizes, 123 color_space, handles, yuvSizes,
164 kTopLeft_GrSurfaceOrigin); 124 kTopLeft_GrSurfaceOrigin);
165 DCHECK(img); 125 DCHECK(img);
166 gl->DeleteTextures(3, source_textures); 126 gl->DeleteTextures(3, source_textures);
167 SyncPointClientImpl client(gl); 127 return skia::AdoptRef(img);
168 video_frame->UpdateReleaseSyncPoint(&client);
169 return make_scoped_ptr(img);
170 } 128 }
171 129
172 bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, 130 bool ShouldCacheVideoFrameSkImage(const VideoFrame* video_frame) {
173 SkBitmap* bitmap, 131 return !video_frame->HasTextures() ||
174 const Context3D& context_3d) { 132 media::VideoFrame::NumPlanes(video_frame->format()) != 1 ||
175 // Check if we could reuse existing texture based bitmap. 133 video_frame->mailbox_holder(0).texture_target != GL_TEXTURE_2D;
176 // Otherwise, release existing texture based bitmap and allocate 134 }
177 // a new one based on video size. 135
178 if (!IsSkBitmapProperlySizedTexture(bitmap, 136 // Creates a SkImage from a |video_frame| backed by native resources.
179 video_frame->visible_rect().size())) { 137 // The SkImage will take ownership of the underlying resource.
180 if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap, 138 skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
181 video_frame->visible_rect().size())) { 139 VideoFrame* video_frame,
182 return false; 140 const Context3D& context_3d) {
183 } 141 DCHECK_EQ(PIXEL_FORMAT_ARGB, video_frame->format());
142
143 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
144 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
145 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
146 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
147 << mailbox_holder.texture_target;
148
149 gpu::gles2::GLES2Interface* gl = context_3d.gl;
150 unsigned source_texture = 0;
151 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
152 // TODO(dcastagna): At the moment Skia doesn't support targets different
153 // than GL_TEXTURE_2D. Avoid this copy once
154 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
155 gl->GenTextures(1, &source_texture);
156 DCHECK(source_texture);
157 gl->BindTexture(GL_TEXTURE_2D, source_texture);
158 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
159 gl, video_frame, source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true,
160 false);
161 } else {
162 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
163 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
164 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
184 } 165 }
185 166 GrBackendTextureDesc desc;
186 unsigned texture_id = 167 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
187 static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); 168 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
188 // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the 169 desc.fWidth = video_frame->coded_size().width();
189 // |texture_id|, it's needed to invalidate the state cached in skia, 170 desc.fHeight = video_frame->coded_size().height();
190 // but currently the state isn't changed. 171 desc.fConfig = kRGBA_8888_GrPixelConfig;
191 172 desc.fTextureHandle = source_texture;
192 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 173 return skia::AdoptRef(
193 context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, 174 SkImage::NewFromAdoptedTexture(context_3d.gr_context, desc));
194 false);
195 bitmap->notifyPixelsChanged();
196 return true;
197 } 175 }
198 176
199 } // anonymous namespace 177 } // anonymous namespace
200 178
201 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. 179 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
202 class VideoImageGenerator : public SkImageGenerator { 180 class VideoImageGenerator : public SkImageGenerator {
203 public: 181 public:
204 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) 182 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame)
205 : SkImageGenerator( 183 : SkImageGenerator(
206 SkImageInfo::MakeN32Premul(frame->visible_rect().width(), 184 SkImageInfo::MakeN32Premul(frame->visible_rect().width(),
207 frame->visible_rect().height())) 185 frame->visible_rect().height())),
208 , frame_(frame) { 186 frame_(frame) {
209 DCHECK(frame_.get()); 187 DCHECK(!frame_->HasTextures());
210 } 188 }
211 ~VideoImageGenerator() override {} 189 ~VideoImageGenerator() override {}
212 190
213 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; }
214
215 protected: 191 protected:
216 bool onGetPixels(const SkImageInfo& info, 192 bool onGetPixels(const SkImageInfo& info,
217 void* pixels, 193 void* pixels,
218 size_t row_bytes, 194 size_t row_bytes,
219 SkPMColor ctable[], 195 SkPMColor ctable[],
220 int* ctable_count) override { 196 int* ctable_count) override {
221 if (!frame_.get())
222 return false;
223 // If skia couldn't do the YUV conversion on GPU, we will on CPU. 197 // If skia couldn't do the YUV conversion on GPU, we will on CPU.
224 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( 198 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(frame_.get(), pixels,
225 frame_, pixels, row_bytes); 199 row_bytes);
226 return true; 200 return true;
227 } 201 }
228 202
229 bool onGetYUV8Planes(SkISize sizes[3], 203 bool onGetYUV8Planes(SkISize sizes[3],
230 void* planes[3], 204 void* planes[3],
231 size_t row_bytes[3], 205 size_t row_bytes[3],
232 SkYUVColorSpace* color_space) override { 206 SkYUVColorSpace* color_space) override {
233 if (!frame_.get() || !media::IsYuvPlanar(frame_->format()) || 207 if (!media::IsYuvPlanar(frame_->format()) ||
234 // TODO(rileya): Skia currently doesn't support YUVA conversion. Remove 208 // TODO(rileya): Skia currently doesn't support YUVA conversion. Remove
235 // this case once it does. As-is we will fall back on the pure-software 209 // this case once it does. As-is we will fall back on the pure-software
236 // path in this case. 210 // path in this case.
237 frame_->format() == PIXEL_FORMAT_YV12A) { 211 frame_->format() == PIXEL_FORMAT_YV12A) {
238 return false; 212 return false;
239 } 213 }
240 214
241 if (color_space) { 215 if (color_space) {
242 if (CheckColorSpace(frame_, COLOR_SPACE_JPEG)) 216 if (CheckColorSpace(frame_.get(), COLOR_SPACE_JPEG))
243 *color_space = kJPEG_SkYUVColorSpace; 217 *color_space = kJPEG_SkYUVColorSpace;
244 else if (CheckColorSpace(frame_, COLOR_SPACE_HD_REC709)) 218 else if (CheckColorSpace(frame_.get(), COLOR_SPACE_HD_REC709))
245 *color_space = kRec709_SkYUVColorSpace; 219 *color_space = kRec709_SkYUVColorSpace;
246 else 220 else
247 *color_space = kRec601_SkYUVColorSpace; 221 *color_space = kRec601_SkYUVColorSpace;
248 } 222 }
249 223
250 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; 224 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
251 ++plane) { 225 ++plane) {
252 if (sizes) { 226 if (sizes) {
253 const gfx::Size size = 227 const gfx::Size size =
254 VideoFrame::PlaneSize(frame_->format(), plane, 228 VideoFrame::PlaneSize(frame_->format(), plane,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 return true; 269 return true;
296 } 270 }
297 271
298 private: 272 private:
299 scoped_refptr<VideoFrame> frame_; 273 scoped_refptr<VideoFrame> frame_;
300 274
301 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); 275 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
302 }; 276 };
303 277
304 SkCanvasVideoRenderer::SkCanvasVideoRenderer() 278 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
305 : last_frame_timestamp_(media::kNoTimestamp()), 279 : last_image_deleting_timer_(
306 frame_deleting_timer_(
307 FROM_HERE, 280 FROM_HERE,
308 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay), 281 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
309 this, 282 this,
310 &SkCanvasVideoRenderer::ResetLastFrame), 283 &SkCanvasVideoRenderer::ResetCache) {}
311 accelerated_generator_(nullptr), 284
312 accelerated_last_frame_timestamp_(media::kNoTimestamp()), 285 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {
313 accelerated_frame_deleting_timer_( 286 ResetCache();
314 FROM_HERE,
315 base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
316 this,
317 &SkCanvasVideoRenderer::ResetAcceleratedLastFrame) {
318 last_frame_.setIsVolatile(true);
319 } 287 }
320 288
321 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
322
323 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, 289 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
324 SkCanvas* canvas, 290 SkCanvas* canvas,
325 const gfx::RectF& dest_rect, 291 const gfx::RectF& dest_rect,
326 uint8 alpha, 292 uint8 alpha,
327 SkXfermode::Mode mode, 293 SkXfermode::Mode mode,
328 VideoRotation video_rotation, 294 VideoRotation video_rotation,
329 const Context3D& context_3d) { 295 const Context3D& context_3d) {
330 if (alpha == 0) { 296 if (alpha == 0) {
331 return; 297 return;
332 } 298 }
333 299
334 SkRect dest; 300 SkRect dest;
335 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); 301 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
336 302
337 SkPaint paint; 303 SkPaint paint;
338 paint.setAlpha(alpha); 304 paint.setAlpha(alpha);
339 305
340 // Paint black rectangle if there isn't a frame available or the 306 // Paint black rectangle if there isn't a frame available or the
341 // frame has an unexpected format. 307 // frame has an unexpected format.
342 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || 308 if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
343 !(media::IsYuvPlanar(video_frame->format()) || 309 !(media::IsYuvPlanar(video_frame->format()) ||
344 video_frame->HasTextures())) { 310 video_frame->HasTextures())) {
345 canvas->drawRect(dest, paint); 311 canvas->drawRect(dest, paint);
346 canvas->flush(); 312 canvas->flush();
347 return; 313 return;
348 } 314 }
349 315
350 SkBitmap* target_frame = nullptr; 316 gpu::gles2::GLES2Interface* gl = context_3d.gl;
351 317
352 if (video_frame->HasTextures()) { 318 if (!last_image_ || video_frame->timestamp() != last_timestamp_) {
353 // Draw HW Video on both SW and HW Canvas. 319 ResetCache();
354 // In SW Canvas case, rely on skia drawing Ganesh SkBitmap on SW SkCanvas. 320 // Generate a new image.
355 if (accelerated_last_frame_.isNull() || 321 // Note: Skia will hold onto |video_frame| via |video_generator| only when
356 video_frame->timestamp() != accelerated_last_frame_timestamp_) { 322 // |video_frame| is software.
357 DCHECK(context_3d.gl); 323 // Holding |video_frame| longer than this call when using GPUVideoDecoder
324 // could cause problems since the pool of VideoFrames has a fixed size.
325 if (video_frame->HasTextures()) {
358 DCHECK(context_3d.gr_context); 326 DCHECK(context_3d.gr_context);
359 if (accelerated_generator_) { 327 DCHECK(gl);
360 // Reset SkBitmap used in SWVideo-to-HWCanvas path. 328 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) {
361 accelerated_last_frame_.reset(); 329 last_image_ =
362 accelerated_generator_ = nullptr; 330 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d);
331 } else {
332 last_image_ =
333 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d);
363 } 334 }
364 335 } else {
365 if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { 336 auto video_generator = new VideoImageGenerator(video_frame);
366 accelerated_last_image_.reset(); 337 last_image_ = skia::AdoptRef(SkImage::NewFromGenerator(video_generator));
367 if (!CopyVideoFrameSingleTextureToSkBitmap(
368 video_frame.get(), &accelerated_last_frame_, context_3d)) {
369 NOTREACHED();
370 return;
371 }
372 DCHECK(video_frame->visible_rect().width() ==
373 accelerated_last_frame_.width() &&
374 video_frame->visible_rect().height() ==
375 accelerated_last_frame_.height());
376 } else {
377 accelerated_last_image_ = CreateSkImageFromVideoFrameYUVTextures(
378 video_frame.get(), context_3d);
379 DCHECK(accelerated_last_image_);
380 }
381 accelerated_last_frame_timestamp_ = video_frame->timestamp();
382 } 338 }
383 target_frame = &accelerated_last_frame_; 339 last_timestamp_ = video_frame->timestamp();
384 accelerated_frame_deleting_timer_.Reset();
385 } else if (canvas->getGrContext()) {
386 if (accelerated_last_frame_.isNull() ||
387 video_frame->timestamp() != accelerated_last_frame_timestamp_) {
388 // Draw SW Video on HW Canvas.
389 if (!accelerated_generator_ && !accelerated_last_frame_.isNull()) {
390 // Reset SkBitmap used in HWVideo-to-HWCanvas path.
391 accelerated_last_frame_.reset();
392 }
393 accelerated_generator_ = new VideoImageGenerator(video_frame);
394
395 // Note: This takes ownership of |accelerated_generator_|.
396 if (!SkInstallDiscardablePixelRef(accelerated_generator_,
397 &accelerated_last_frame_)) {
398 NOTREACHED();
399 return;
400 }
401 DCHECK(video_frame->visible_rect().width() ==
402 accelerated_last_frame_.width() &&
403 video_frame->visible_rect().height() ==
404 accelerated_last_frame_.height());
405
406 accelerated_last_frame_timestamp_ = video_frame->timestamp();
407 } else if (accelerated_generator_) {
408 accelerated_generator_->set_frame(video_frame);
409 }
410 target_frame = &accelerated_last_frame_;
411 accelerated_frame_deleting_timer_.Reset();
412 } else {
413 // Draw SW Video on SW Canvas.
414 DCHECK(video_frame->IsMappable());
415 if (last_frame_.isNull() ||
416 video_frame->timestamp() != last_frame_timestamp_) {
417 // Check if |bitmap| needs to be (re)allocated.
418 if (last_frame_.isNull() ||
419 last_frame_.width() != video_frame->visible_rect().width() ||
420 last_frame_.height() != video_frame->visible_rect().height()) {
421 last_frame_.allocN32Pixels(video_frame->visible_rect().width(),
422 video_frame->visible_rect().height());
423 last_frame_.setIsVolatile(true);
424 }
425 last_frame_.lockPixels();
426 ConvertVideoFrameToRGBPixels(
427 video_frame, last_frame_.getPixels(), last_frame_.rowBytes());
428 last_frame_.notifyPixelsChanged();
429 last_frame_.unlockPixels();
430 last_frame_timestamp_ = video_frame->timestamp();
431 }
432 target_frame = &last_frame_;
433 frame_deleting_timer_.Reset();
434 } 340 }
341 last_image_deleting_timer_.Reset();
435 342
436 paint.setXfermodeMode(mode); 343 paint.setXfermodeMode(mode);
437 paint.setFilterQuality(kLow_SkFilterQuality); 344 paint.setFilterQuality(kLow_SkFilterQuality);
438 345
439 const bool need_transform = 346 const bool need_transform =
440 video_rotation != VIDEO_ROTATION_0 || 347 video_rotation != VIDEO_ROTATION_0 ||
441 dest_rect.size() != video_frame->visible_rect().size() || 348 dest_rect.size() != video_frame->visible_rect().size() ||
442 !dest_rect.origin().IsOrigin(); 349 !dest_rect.origin().IsOrigin();
443 if (need_transform) { 350 if (need_transform) {
444 canvas->save(); 351 canvas->save();
(...skipping 16 matching lines...) Expand all
461 } 368 }
462 canvas->rotate(angle); 369 canvas->rotate(angle);
463 370
464 gfx::SizeF rotated_dest_size = dest_rect.size(); 371 gfx::SizeF rotated_dest_size = dest_rect.size();
465 if (video_rotation == VIDEO_ROTATION_90 || 372 if (video_rotation == VIDEO_ROTATION_90 ||
466 video_rotation == VIDEO_ROTATION_270) { 373 video_rotation == VIDEO_ROTATION_270) {
467 rotated_dest_size = 374 rotated_dest_size =
468 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width()); 375 gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
469 } 376 }
470 canvas->scale( 377 canvas->scale(
471 SkFloatToScalar(rotated_dest_size.width() / target_frame->width()), 378 SkFloatToScalar(rotated_dest_size.width() / last_image_->width()),
472 SkFloatToScalar(rotated_dest_size.height() / target_frame->height())); 379 SkFloatToScalar(rotated_dest_size.height() / last_image_->height()));
473 canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), 380 canvas->translate(-SkFloatToScalar(last_image_->width() * 0.5f),
474 -SkFloatToScalar(target_frame->height() * 0.5f)); 381 -SkFloatToScalar(last_image_->height() * 0.5f));
475 } 382 }
476 if (accelerated_last_image_) { 383 canvas->drawImage(last_image_.get(), 0, 0, &paint);
477 canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); 384
478 } else {
479 canvas->drawBitmap(*target_frame, 0, 0, &paint);
480 }
481 if (need_transform) 385 if (need_transform)
482 canvas->restore(); 386 canvas->restore();
387 // Make sure to flush so we can remove the videoframe from the generator.
483 canvas->flush(); 388 canvas->flush();
484 // SkCanvas::flush() causes the generator to generate SkImage, so delete 389
485 // |video_frame| not to be outlived. 390 if (!ShouldCacheVideoFrameSkImage(video_frame.get()))
486 if (canvas->getGrContext() && accelerated_generator_) 391 ResetCache();
487 accelerated_generator_->set_frame(nullptr); 392
393 if (video_frame->HasTextures()) {
394 DCHECK(gl);
395 SyncPointClientImpl client(gl);
396 video_frame->UpdateReleaseSyncPoint(&client);
397 }
488 } 398 }
489 399
490 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, 400 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
491 SkCanvas* canvas, 401 SkCanvas* canvas,
492 const Context3D& context_3d) { 402 const Context3D& context_3d) {
493 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, 403 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff,
494 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d); 404 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, context_3d);
495 } 405 }
496 406
497 // static 407 // static
498 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( 408 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
499 const scoped_refptr<VideoFrame>& video_frame, 409 const VideoFrame* video_frame,
500 void* rgb_pixels, 410 void* rgb_pixels,
501 size_t row_bytes) { 411 size_t row_bytes) {
502 if (!video_frame->IsMappable()) { 412 if (!video_frame->IsMappable()) {
503 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats."; 413 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats.";
504 return; 414 return;
505 } 415 }
506 if (!media::IsYuvPlanar(video_frame->format())) { 416 if (!media::IsYuvPlanar(video_frame->format())) {
507 NOTREACHED() << "Non YUV formats are not supported"; 417 NOTREACHED() << "Non YUV formats are not supported";
508 return; 418 return;
509 } 419 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 unsigned int type, 547 unsigned int type,
638 bool premultiply_alpha, 548 bool premultiply_alpha,
639 bool flip_y) { 549 bool flip_y) {
640 DCHECK(video_frame); 550 DCHECK(video_frame);
641 DCHECK(video_frame->HasTextures()); 551 DCHECK(video_frame->HasTextures());
642 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format())); 552 DCHECK_EQ(1u, VideoFrame::NumPlanes(video_frame->format()));
643 553
644 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 554 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
645 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 555 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
646 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 556 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
647 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES); 557 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
558 << mailbox_holder.texture_target;
648 559
649 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); 560 gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
650 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 561 uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
651 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 562 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
652 563
653 // The video is stored in a unmultiplied format, so premultiply 564 // The video is stored in a unmultiplied format, so premultiply
654 // if necessary. 565 // if necessary.
655 // Application itself needs to take care of setting the right |flip_y| 566 // Application itself needs to take care of setting the right |flip_y|
656 // value down to get the expected result. 567 // value down to get the expected result.
657 // "flip_y == true" means to reverse the video orientation while 568 // "flip_y == true" means to reverse the video orientation while
658 // "flip_y == false" means to keep the intrinsic orientation. 569 // "flip_y == false" means to keep the intrinsic orientation.
659 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture, 570 gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture,
660 internal_format, type, 571 internal_format, type,
661 flip_y, premultiply_alpha, false); 572 flip_y, premultiply_alpha, false);
662 573
663 gl->DeleteTextures(1, &source_texture); 574 gl->DeleteTextures(1, &source_texture);
664 gl->Flush(); 575 gl->Flush();
665 576
666 SyncPointClientImpl client(gl); 577 SyncPointClientImpl client(gl);
667 video_frame->UpdateReleaseSyncPoint(&client); 578 video_frame->UpdateReleaseSyncPoint(&client);
668 } 579 }
669 580
670 void SkCanvasVideoRenderer::ResetLastFrame() { 581 void SkCanvasVideoRenderer::ResetCache() {
671 last_frame_.reset(); 582 // Clear cached values.
672 last_frame_timestamp_ = media::kNoTimestamp(); 583 last_image_ = nullptr;
673 } 584 last_timestamp_ = kNoTimestamp();
674
675 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() {
676 accelerated_last_image_.reset();
677 accelerated_last_frame_.reset();
678 accelerated_generator_ = nullptr;
679 accelerated_last_frame_timestamp_ = media::kNoTimestamp();
680 } 585 }
681 586
682 } // namespace media 587 } // 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