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/filters/skcanvas_video_renderer.h" | 5 #include "media/filters/skcanvas_video_renderer.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "media/base/video_frame.h" | 8 #include "media/base/video_frame.h" |
9 #include "media/base/yuv_convert.h" | 9 #include "media/base/yuv_convert.h" |
10 #include "third_party/libyuv/include/libyuv.h" | 10 #include "third_party/libyuv/include/libyuv.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 SK_A32_SHIFT == 24 | 22 SK_A32_SHIFT == 24 |
23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR | 23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR |
24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR | 24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR |
25 #else | 25 #else |
26 #error Unexpected Skia ARGB_8888 layout! | 26 #error Unexpected Skia ARGB_8888 layout! |
27 #endif | 27 #endif |
28 | 28 |
29 namespace media { | 29 namespace media { |
30 | 30 |
31 static bool IsYUV(media::VideoFrame::Format format) { | 31 static bool IsYUV(media::VideoFrame::Format format) { |
32 return format == media::VideoFrame::YV12 || | 32 switch (format) { |
33 format == media::VideoFrame::YV16 || | 33 case VideoFrame::YV12: |
34 format == media::VideoFrame::I420 || | 34 case VideoFrame::YV16: |
35 format == media::VideoFrame::YV12A || | 35 case VideoFrame::I420: |
36 format == media::VideoFrame::YV12J || | 36 case VideoFrame::YV12A: |
37 format == media::VideoFrame::YV24; | 37 case VideoFrame::YV12J: |
| 38 case VideoFrame::YV24: |
| 39 case VideoFrame::NV12: |
| 40 return true; |
| 41 case VideoFrame::UNKNOWN: |
| 42 case VideoFrame::NATIVE_TEXTURE: |
| 43 #if defined(VIDEO_HOLE) |
| 44 case VideoFrame::HOLE: |
| 45 #endif // defined(VIDEO_HOLE) |
| 46 return false; |
| 47 } |
| 48 NOTREACHED() << "Invalid videoframe format provided: " << format; |
| 49 return false; |
| 50 } |
| 51 |
| 52 static bool IsJPEGColorSpace(media::VideoFrame::Format format) { |
| 53 switch (format) { |
| 54 case VideoFrame::YV12J: |
| 55 return true; |
| 56 case VideoFrame::YV12: |
| 57 case VideoFrame::YV16: |
| 58 case VideoFrame::I420: |
| 59 case VideoFrame::YV12A: |
| 60 case VideoFrame::YV24: |
| 61 case VideoFrame::NV12: |
| 62 case VideoFrame::UNKNOWN: |
| 63 case VideoFrame::NATIVE_TEXTURE: |
| 64 #if defined(VIDEO_HOLE) |
| 65 case VideoFrame::HOLE: |
| 66 #endif // defined(VIDEO_HOLE) |
| 67 return false; |
| 68 } |
| 69 NOTREACHED() << "Invalid videoframe format provided: " << format; |
| 70 return false; |
38 } | 71 } |
39 | 72 |
40 static bool IsYUVOrNative(media::VideoFrame::Format format) { | 73 static bool IsYUVOrNative(media::VideoFrame::Format format) { |
41 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; | 74 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
42 } | 75 } |
43 | 76 |
44 // Converts a |video_frame| to raw |rgb_pixels|. | 77 // Converts a |video_frame| to raw |rgb_pixels|. |
45 static void ConvertVideoFrameToRGBPixels( | 78 static void ConvertVideoFrameToRGBPixels( |
46 const scoped_refptr<media::VideoFrame>& video_frame, | 79 const scoped_refptr<media::VideoFrame>& video_frame, |
47 void* rgb_pixels, | 80 void* rgb_pixels, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 break; | 204 break; |
172 } | 205 } |
173 } | 206 } |
174 | 207 |
175 // Generates an RGB image from a VideoFrame. | 208 // Generates an RGB image from a VideoFrame. |
176 class VideoImageGenerator : public SkImageGenerator { | 209 class VideoImageGenerator : public SkImageGenerator { |
177 public: | 210 public: |
178 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {} | 211 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {} |
179 virtual ~VideoImageGenerator() {} | 212 virtual ~VideoImageGenerator() {} |
180 | 213 |
| 214 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } |
| 215 |
181 protected: | 216 protected: |
182 virtual bool onGetInfo(SkImageInfo* info) OVERRIDE { | 217 virtual bool onGetInfo(SkImageInfo* info) OVERRIDE { |
183 info->fWidth = frame_->visible_rect().width(); | 218 info->fWidth = frame_->visible_rect().width(); |
184 info->fHeight = frame_->visible_rect().height(); | 219 info->fHeight = frame_->visible_rect().height(); |
185 info->fColorType = kN32_SkColorType; | 220 info->fColorType = kN32_SkColorType; |
186 info->fAlphaType = kPremul_SkAlphaType; | 221 info->fAlphaType = kPremul_SkAlphaType; |
187 return true; | 222 return true; |
188 } | 223 } |
189 | 224 |
190 virtual bool onGetPixels(const SkImageInfo& info, | 225 virtual bool onGetPixels(const SkImageInfo& info, |
191 void* pixels, | 226 void* pixels, |
192 size_t row_bytes, | 227 size_t row_bytes, |
193 SkPMColor ctable[], | 228 SkPMColor ctable[], |
194 int* ctable_count) OVERRIDE { | 229 int* ctable_count) OVERRIDE { |
195 if (!frame_.get()) | 230 if (!frame_.get()) |
196 return false; | 231 return false; |
197 if (!pixels) | 232 if (!pixels) |
198 return true; | 233 return true; |
199 // If skia couldn't do the YUV conversion, we will. | 234 // If skia couldn't do the YUV conversion, we will. |
200 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes); | 235 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes); |
201 frame_ = NULL; | 236 frame_ = NULL; |
202 return true; | 237 return true; |
203 } | 238 } |
204 | 239 |
205 virtual bool onGetYUV8Planes(SkISize sizes[3], | 240 virtual bool onGetYUV8Planes(SkISize sizes[3], |
206 void* planes[3], | 241 void* planes[3], |
207 size_t row_bytes[3]) OVERRIDE { | 242 size_t row_bytes[3], |
208 if (!frame_.get()) | 243 SkYUVColorSpace* color_space) OVERRIDE { |
| 244 if (!frame_.get() || !IsYUV(frame_->format())) |
209 return false; | 245 return false; |
210 // Currently Skia only supports JPEG color range YUV. | 246 |
211 if (frame_->format() != VideoFrame::YV12J) | 247 if (color_space) { |
212 return false; | 248 if (IsJPEGColorSpace(frame_->format())) |
| 249 *color_space = kJPEG_SkYUVColorSpace; |
| 250 else |
| 251 *color_space = kRec601_SkYUVColorSpace; |
| 252 } |
| 253 |
213 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; | 254 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; |
214 ++plane) { | 255 ++plane) { |
215 if (sizes) { | 256 if (sizes) { |
216 gfx::Size size; | 257 gfx::Size size; |
217 size = VideoFrame::PlaneSize( | 258 size = |
218 frame_->format(), plane, frame_->coded_size()); | 259 VideoFrame::PlaneSize(frame_->format(), |
| 260 plane, |
| 261 gfx::Size(frame_->visible_rect().width(), |
| 262 frame_->visible_rect().height())); |
219 sizes[plane].set(size.width(), size.height()); | 263 sizes[plane].set(size.width(), size.height()); |
220 } | 264 } |
221 if (row_bytes) | 265 if (row_bytes && planes) { |
222 row_bytes[plane] = frame_->stride(plane); | 266 size_t offset; |
223 if (planes) | 267 int y_shift = (frame_->format() == media::VideoFrame::YV16) ? 0 : 1; |
224 planes[plane] = frame_->data(plane); | 268 if (plane == media::VideoFrame::kYPlane) { |
| 269 offset = (frame_->stride(media::VideoFrame::kYPlane) * |
| 270 frame_->visible_rect().y()) + |
| 271 frame_->visible_rect().x(); |
| 272 } else { |
| 273 offset = (frame_->stride(media::VideoFrame::kUPlane) * |
| 274 (frame_->visible_rect().y() >> y_shift)) + |
| 275 (frame_->visible_rect().x() >> 1); |
| 276 } |
| 277 row_bytes[plane] = static_cast<size_t>(frame_->stride(plane)); |
| 278 planes[plane] = frame_->data(plane) + offset; |
| 279 } |
225 } | 280 } |
226 if (planes && row_bytes) | 281 if (planes && row_bytes) |
227 frame_ = NULL; | 282 frame_ = NULL; |
228 return true; | 283 return true; |
229 } | 284 } |
230 public: | |
231 | |
232 virtual void set_frame(const scoped_refptr<VideoFrame>& frame) { | |
233 frame_ = frame; | |
234 } | |
235 | 285 |
236 private: | 286 private: |
237 scoped_refptr<VideoFrame> frame_; | 287 scoped_refptr<VideoFrame> frame_; |
238 }; | 288 }; |
239 | 289 |
240 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 290 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
241 : generator_(NULL), | 291 : generator_(NULL), last_frame_timestamp_(media::kNoTimestamp()) { |
242 last_frame_timestamp_(media::kNoTimestamp()) { | |
243 last_frame_.setIsVolatile(true); | 292 last_frame_.setIsVolatile(true); |
244 } | 293 } |
245 | 294 |
246 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 295 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
247 | 296 |
248 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, | 297 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
249 SkCanvas* canvas, | 298 SkCanvas* canvas, |
250 const gfx::RectF& dest_rect, | 299 const gfx::RectF& dest_rect, |
251 uint8 alpha, | 300 uint8 alpha, |
252 SkXfermode::Mode mode, | 301 SkXfermode::Mode mode, |
253 VideoRotation video_rotation) { | 302 VideoRotation video_rotation) { |
254 if (alpha == 0) { | 303 if (alpha == 0) { |
255 return; | 304 return; |
256 } | 305 } |
257 | 306 |
258 SkRect dest; | 307 SkRect dest; |
259 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 308 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
260 | 309 |
261 SkPaint paint; | 310 SkPaint paint; |
262 paint.setAlpha(alpha); | 311 paint.setAlpha(alpha); |
263 | 312 |
264 // Paint black rectangle if there isn't a frame available or the | 313 // Paint black rectangle if there isn't a frame available or the |
265 // frame has an unexpected format. | 314 // frame has an unexpected format. |
266 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { | 315 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { |
267 canvas->drawRect(dest, paint); | 316 canvas->drawRect(dest, paint); |
| 317 canvas->flush(); |
268 return; | 318 return; |
269 } | 319 } |
270 | 320 |
271 // Check if we should convert and update |last_frame_|. | 321 // Check if we should convert and update |last_frame_|. |
272 if (last_frame_.isNull() || | 322 if (last_frame_.isNull() || |
273 video_frame->timestamp() != last_frame_timestamp_) { | 323 video_frame->timestamp() != last_frame_timestamp_) { |
274 generator_ = new VideoImageGenerator(video_frame); | 324 generator_ = new VideoImageGenerator(video_frame); |
275 | 325 |
276 // Note: This takes ownership of |generator_|. | 326 // Note: This takes ownership of |generator_|. |
277 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { | 327 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { |
(...skipping 12 matching lines...) Expand all Loading... |
290 case VIDEO_ROTATION_180: | 340 case VIDEO_ROTATION_180: |
291 last_frame_ = SkBitmapOperations::Rotate( | 341 last_frame_ = SkBitmapOperations::Rotate( |
292 last_frame_, SkBitmapOperations::ROTATION_180_CW); | 342 last_frame_, SkBitmapOperations::ROTATION_180_CW); |
293 break; | 343 break; |
294 case VIDEO_ROTATION_270: | 344 case VIDEO_ROTATION_270: |
295 last_frame_ = SkBitmapOperations::Rotate( | 345 last_frame_ = SkBitmapOperations::Rotate( |
296 last_frame_, SkBitmapOperations::ROTATION_270_CW); | 346 last_frame_, SkBitmapOperations::ROTATION_270_CW); |
297 break; | 347 break; |
298 } | 348 } |
299 | 349 |
| 350 // We copied the frame into a new bitmap and threw out the old one, so we |
| 351 // no longer have a |generator_| around. This should be removed when the |
| 352 // above TODO is addressed. |
| 353 if (video_rotation != VIDEO_ROTATION_0) |
| 354 generator_ = NULL; |
| 355 |
300 last_frame_timestamp_ = video_frame->timestamp(); | 356 last_frame_timestamp_ = video_frame->timestamp(); |
301 } else { | 357 } else if (generator_) { |
302 generator_->set_frame(video_frame); | 358 generator_->set_frame(video_frame); |
303 } | 359 } |
304 | 360 |
305 paint.setXfermodeMode(mode); | 361 paint.setXfermodeMode(mode); |
306 | 362 |
307 // Paint using |last_frame_|. | 363 // Paint using |last_frame_|. |
308 paint.setFilterLevel(SkPaint::kLow_FilterLevel); | 364 paint.setFilterLevel(SkPaint::kLow_FilterLevel); |
309 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); | 365 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); |
| 366 canvas->flush(); |
310 } | 367 } |
311 | 368 |
312 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 369 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
313 SkCanvas* canvas) { | 370 SkCanvas* canvas) { |
314 Paint(video_frame, | 371 Paint(video_frame, |
315 canvas, | 372 canvas, |
316 video_frame->visible_rect(), | 373 video_frame->visible_rect(), |
317 0xff, | 374 0xff, |
318 SkXfermode::kSrc_Mode, | 375 SkXfermode::kSrc_Mode, |
319 media::VIDEO_ROTATION_0); | 376 media::VIDEO_ROTATION_0); |
320 } | 377 } |
321 | 378 |
322 } // namespace media | 379 } // namespace media |
OLD | NEW |