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 "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" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 return false; | 84 return false; |
85 } | 85 } |
86 NOTREACHED() << "Invalid videoframe format provided: " << format; | 86 NOTREACHED() << "Invalid videoframe format provided: " << format; |
87 return false; | 87 return false; |
88 } | 88 } |
89 | 89 |
90 bool IsYUVOrNative(media::VideoFrame::Format format) { | 90 bool IsYUVOrNative(media::VideoFrame::Format format) { |
91 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; | 91 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
92 } | 92 } |
93 | 93 |
94 // Converts a |video_frame| to raw |rgb_pixels|. | |
95 void ConvertVideoFrameToRGBPixels( | |
96 const scoped_refptr<media::VideoFrame>& video_frame, | |
97 void* rgb_pixels, | |
98 size_t row_bytes) { | |
99 DCHECK(IsYUVOrNative(video_frame->format())) | |
100 << video_frame->format(); | |
101 if (IsYUV(video_frame->format())) { | |
102 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | |
103 video_frame->stride(media::VideoFrame::kVPlane)); | |
104 } | |
105 | |
106 size_t y_offset = 0; | |
107 size_t uv_offset = 0; | |
108 if (IsYUV(video_frame->format())) { | |
109 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; | |
110 // Use the "left" and "top" of the destination rect to locate the offset | |
111 // in Y, U and V planes. | |
112 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * | |
113 video_frame->visible_rect().y()) + | |
114 video_frame->visible_rect().x(); | |
115 // For format YV12, there is one U, V value per 2x2 block. | |
116 // For format YV16, there is one U, V value per 2x1 block. | |
117 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * | |
118 (video_frame->visible_rect().y() >> y_shift)) + | |
119 (video_frame->visible_rect().x() >> 1); | |
120 } | |
121 | |
122 switch (video_frame->format()) { | |
123 case VideoFrame::YV12: | |
124 case VideoFrame::I420: | |
125 LIBYUV_I420_TO_ARGB( | |
126 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
127 video_frame->stride(VideoFrame::kYPlane), | |
128 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
129 video_frame->stride(VideoFrame::kUPlane), | |
130 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
131 video_frame->stride(VideoFrame::kVPlane), | |
132 static_cast<uint8*>(rgb_pixels), | |
133 row_bytes, | |
134 video_frame->visible_rect().width(), | |
135 video_frame->visible_rect().height()); | |
136 break; | |
137 | |
138 case VideoFrame::YV12J: | |
139 ConvertYUVToRGB32( | |
140 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
141 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
142 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
143 static_cast<uint8*>(rgb_pixels), | |
144 video_frame->visible_rect().width(), | |
145 video_frame->visible_rect().height(), | |
146 video_frame->stride(VideoFrame::kYPlane), | |
147 video_frame->stride(VideoFrame::kUPlane), | |
148 row_bytes, | |
149 YV12J); | |
150 break; | |
151 | |
152 case VideoFrame::YV12HD: | |
153 ConvertYUVToRGB32( | |
154 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
155 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
156 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
157 static_cast<uint8*>(rgb_pixels), | |
158 video_frame->visible_rect().width(), | |
159 video_frame->visible_rect().height(), | |
160 video_frame->stride(VideoFrame::kYPlane), | |
161 video_frame->stride(VideoFrame::kUPlane), | |
162 row_bytes, | |
163 YV12HD); | |
164 break; | |
165 | |
166 case VideoFrame::YV16: | |
167 LIBYUV_I422_TO_ARGB( | |
168 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
169 video_frame->stride(VideoFrame::kYPlane), | |
170 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
171 video_frame->stride(VideoFrame::kUPlane), | |
172 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
173 video_frame->stride(VideoFrame::kVPlane), | |
174 static_cast<uint8*>(rgb_pixels), | |
175 row_bytes, | |
176 video_frame->visible_rect().width(), | |
177 video_frame->visible_rect().height()); | |
178 break; | |
179 | |
180 case VideoFrame::YV12A: | |
181 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM | |
182 // optimized. | |
183 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel. | |
184 ConvertYUVAToARGB( | |
185 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
186 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
187 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
188 video_frame->data(VideoFrame::kAPlane), | |
189 static_cast<uint8*>(rgb_pixels), | |
190 video_frame->visible_rect().width(), | |
191 video_frame->visible_rect().height(), | |
192 video_frame->stride(VideoFrame::kYPlane), | |
193 video_frame->stride(VideoFrame::kUPlane), | |
194 video_frame->stride(VideoFrame::kAPlane), | |
195 row_bytes, | |
196 YV12); | |
197 break; | |
198 | |
199 case VideoFrame::YV24: | |
200 libyuv::I444ToARGB( | |
201 video_frame->data(VideoFrame::kYPlane) + y_offset, | |
202 video_frame->stride(VideoFrame::kYPlane), | |
203 video_frame->data(VideoFrame::kUPlane) + uv_offset, | |
204 video_frame->stride(VideoFrame::kUPlane), | |
205 video_frame->data(VideoFrame::kVPlane) + uv_offset, | |
206 video_frame->stride(VideoFrame::kVPlane), | |
207 static_cast<uint8*>(rgb_pixels), | |
208 row_bytes, | |
209 video_frame->visible_rect().width(), | |
210 video_frame->visible_rect().height()); | |
211 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ | |
212 SK_A32_SHIFT == 24 | |
213 libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels), | |
214 row_bytes, | |
215 static_cast<uint8*>(rgb_pixels), | |
216 row_bytes, | |
217 video_frame->visible_rect().width(), | |
218 video_frame->visible_rect().height()); | |
219 #endif | |
220 break; | |
221 | |
222 case VideoFrame::NATIVE_TEXTURE: { | |
223 SkBitmap tmp; | |
224 tmp.installPixels( | |
225 SkImageInfo::MakeN32Premul(video_frame->visible_rect().width(), | |
226 video_frame->visible_rect().height()), | |
227 rgb_pixels, | |
228 row_bytes); | |
229 video_frame->ReadPixelsFromNativeTexture(tmp); | |
230 break; | |
231 } | |
232 | |
233 #if defined(VIDEO_HOLE) | |
234 case VideoFrame::HOLE: | |
235 #endif // defined(VIDEO_HOLE) | |
236 case VideoFrame::ARGB: | |
237 case VideoFrame::UNKNOWN: | |
238 case VideoFrame::NV12: | |
239 NOTREACHED(); | |
240 } | |
241 } | |
242 | |
243 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap, | 94 bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap, |
244 const gfx::Size& size) { | 95 const gfx::Size& size) { |
245 return bitmap->getTexture() && bitmap->width() == size.width() && | 96 return bitmap->getTexture() && bitmap->width() == size.width() && |
246 bitmap->height() == size.height(); | 97 bitmap->height() == size.height(); |
247 } | 98 } |
248 | 99 |
249 bool AllocateSkBitmapTexture(GrContext* gr, | 100 bool AllocateSkBitmapTexture(GrContext* gr, |
250 SkBitmap* bitmap, | 101 SkBitmap* bitmap, |
251 const gfx::Size& size) { | 102 const gfx::Size& size) { |
252 DCHECK(gr); | 103 DCHECK(gr); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 bool onGetPixels(const SkImageInfo& info, | 188 bool onGetPixels(const SkImageInfo& info, |
338 void* pixels, | 189 void* pixels, |
339 size_t row_bytes, | 190 size_t row_bytes, |
340 SkPMColor ctable[], | 191 SkPMColor ctable[], |
341 int* ctable_count) override { | 192 int* ctable_count) override { |
342 if (!frame_.get()) | 193 if (!frame_.get()) |
343 return false; | 194 return false; |
344 if (!pixels) | 195 if (!pixels) |
345 return false; | 196 return false; |
346 // 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. |
347 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes); | 198 SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| 199 frame_, pixels, row_bytes); |
348 return true; | 200 return true; |
349 } | 201 } |
350 | 202 |
351 bool onGetYUV8Planes(SkISize sizes[3], | 203 bool onGetYUV8Planes(SkISize sizes[3], |
352 void* planes[3], | 204 void* planes[3], |
353 size_t row_bytes[3], | 205 size_t row_bytes[3], |
354 SkYUVColorSpace* color_space) override { | 206 SkYUVColorSpace* color_space) override { |
355 if (!frame_.get() || !IsYUV(frame_->format()) || | 207 if (!frame_.get() || !IsYUV(frame_->format()) || |
356 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion, | 208 // TODO(rileya): Skia currently doesn't support Rec709 YUV conversion, |
357 // Remove this case once it does. As-is we will fall back on the | 209 // Remove this case once it does. As-is we will fall back on the |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 accelerated_generator_->set_frame(nullptr); | 417 accelerated_generator_->set_frame(nullptr); |
566 } | 418 } |
567 | 419 |
568 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 420 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
569 SkCanvas* canvas) { | 421 SkCanvas* canvas) { |
570 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, | 422 Paint(video_frame, canvas, video_frame->visible_rect(), 0xff, |
571 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, Context3D()); | 423 SkXfermode::kSrc_Mode, media::VIDEO_ROTATION_0, Context3D()); |
572 } | 424 } |
573 | 425 |
574 // static | 426 // static |
| 427 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| 428 const scoped_refptr<media::VideoFrame>& video_frame, |
| 429 void* rgb_pixels, |
| 430 size_t row_bytes) { |
| 431 DCHECK(IsYUVOrNative(video_frame->format())) |
| 432 << video_frame->format(); |
| 433 if (IsYUV(video_frame->format())) { |
| 434 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
| 435 video_frame->stride(media::VideoFrame::kVPlane)); |
| 436 } |
| 437 |
| 438 size_t y_offset = 0; |
| 439 size_t uv_offset = 0; |
| 440 if (IsYUV(video_frame->format())) { |
| 441 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; |
| 442 // Use the "left" and "top" of the destination rect to locate the offset |
| 443 // in Y, U and V planes. |
| 444 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * |
| 445 video_frame->visible_rect().y()) + |
| 446 video_frame->visible_rect().x(); |
| 447 // For format YV12, there is one U, V value per 2x2 block. |
| 448 // For format YV16, there is one U, V value per 2x1 block. |
| 449 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * |
| 450 (video_frame->visible_rect().y() >> y_shift)) + |
| 451 (video_frame->visible_rect().x() >> 1); |
| 452 } |
| 453 |
| 454 switch (video_frame->format()) { |
| 455 case VideoFrame::YV12: |
| 456 case VideoFrame::I420: |
| 457 LIBYUV_I420_TO_ARGB( |
| 458 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 459 video_frame->stride(VideoFrame::kYPlane), |
| 460 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 461 video_frame->stride(VideoFrame::kUPlane), |
| 462 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 463 video_frame->stride(VideoFrame::kVPlane), |
| 464 static_cast<uint8*>(rgb_pixels), |
| 465 row_bytes, |
| 466 video_frame->visible_rect().width(), |
| 467 video_frame->visible_rect().height()); |
| 468 break; |
| 469 |
| 470 case VideoFrame::YV12J: |
| 471 ConvertYUVToRGB32( |
| 472 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 473 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 474 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 475 static_cast<uint8*>(rgb_pixels), |
| 476 video_frame->visible_rect().width(), |
| 477 video_frame->visible_rect().height(), |
| 478 video_frame->stride(VideoFrame::kYPlane), |
| 479 video_frame->stride(VideoFrame::kUPlane), |
| 480 row_bytes, |
| 481 YV12J); |
| 482 break; |
| 483 |
| 484 case VideoFrame::YV12HD: |
| 485 ConvertYUVToRGB32( |
| 486 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 487 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 488 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 489 static_cast<uint8*>(rgb_pixels), |
| 490 video_frame->visible_rect().width(), |
| 491 video_frame->visible_rect().height(), |
| 492 video_frame->stride(VideoFrame::kYPlane), |
| 493 video_frame->stride(VideoFrame::kUPlane), |
| 494 row_bytes, |
| 495 YV12HD); |
| 496 break; |
| 497 |
| 498 case VideoFrame::YV16: |
| 499 LIBYUV_I422_TO_ARGB( |
| 500 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 501 video_frame->stride(VideoFrame::kYPlane), |
| 502 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 503 video_frame->stride(VideoFrame::kUPlane), |
| 504 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 505 video_frame->stride(VideoFrame::kVPlane), |
| 506 static_cast<uint8*>(rgb_pixels), |
| 507 row_bytes, |
| 508 video_frame->visible_rect().width(), |
| 509 video_frame->visible_rect().height()); |
| 510 break; |
| 511 |
| 512 case VideoFrame::YV12A: |
| 513 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM |
| 514 // optimized. |
| 515 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel. |
| 516 ConvertYUVAToARGB( |
| 517 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 518 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 519 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 520 video_frame->data(VideoFrame::kAPlane), |
| 521 static_cast<uint8*>(rgb_pixels), |
| 522 video_frame->visible_rect().width(), |
| 523 video_frame->visible_rect().height(), |
| 524 video_frame->stride(VideoFrame::kYPlane), |
| 525 video_frame->stride(VideoFrame::kUPlane), |
| 526 video_frame->stride(VideoFrame::kAPlane), |
| 527 row_bytes, |
| 528 YV12); |
| 529 break; |
| 530 |
| 531 case VideoFrame::YV24: |
| 532 libyuv::I444ToARGB( |
| 533 video_frame->data(VideoFrame::kYPlane) + y_offset, |
| 534 video_frame->stride(VideoFrame::kYPlane), |
| 535 video_frame->data(VideoFrame::kUPlane) + uv_offset, |
| 536 video_frame->stride(VideoFrame::kUPlane), |
| 537 video_frame->data(VideoFrame::kVPlane) + uv_offset, |
| 538 video_frame->stride(VideoFrame::kVPlane), |
| 539 static_cast<uint8*>(rgb_pixels), |
| 540 row_bytes, |
| 541 video_frame->visible_rect().width(), |
| 542 video_frame->visible_rect().height()); |
| 543 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ |
| 544 SK_A32_SHIFT == 24 |
| 545 libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels), |
| 546 row_bytes, |
| 547 static_cast<uint8*>(rgb_pixels), |
| 548 row_bytes, |
| 549 video_frame->visible_rect().width(), |
| 550 video_frame->visible_rect().height()); |
| 551 #endif |
| 552 break; |
| 553 |
| 554 case VideoFrame::NATIVE_TEXTURE: { |
| 555 SkBitmap tmp; |
| 556 tmp.installPixels( |
| 557 SkImageInfo::MakeN32Premul(video_frame->visible_rect().width(), |
| 558 video_frame->visible_rect().height()), |
| 559 rgb_pixels, |
| 560 row_bytes); |
| 561 video_frame->ReadPixelsFromNativeTexture(tmp); |
| 562 break; |
| 563 } |
| 564 |
| 565 #if defined(VIDEO_HOLE) |
| 566 case VideoFrame::HOLE: |
| 567 #endif // defined(VIDEO_HOLE) |
| 568 case VideoFrame::ARGB: |
| 569 case VideoFrame::UNKNOWN: |
| 570 case VideoFrame::NV12: |
| 571 NOTREACHED(); |
| 572 } |
| 573 } |
| 574 |
| 575 // static |
575 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( | 576 void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( |
576 gpu::gles2::GLES2Interface* gl, | 577 gpu::gles2::GLES2Interface* gl, |
577 VideoFrame* video_frame, | 578 VideoFrame* video_frame, |
578 unsigned int texture, | 579 unsigned int texture, |
579 unsigned int level, | 580 unsigned int level, |
580 unsigned int internal_format, | 581 unsigned int internal_format, |
581 unsigned int type, | 582 unsigned int type, |
582 bool premultiply_alpha, | 583 bool premultiply_alpha, |
583 bool flip_y) { | 584 bool flip_y) { |
584 DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE); | 585 DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 last_frame_timestamp_ = media::kNoTimestamp(); | 617 last_frame_timestamp_ = media::kNoTimestamp(); |
617 } | 618 } |
618 | 619 |
619 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { | 620 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { |
620 accelerated_last_frame_.reset(); | 621 accelerated_last_frame_.reset(); |
621 accelerated_generator_ = nullptr; | 622 accelerated_generator_ = nullptr; |
622 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); | 623 accelerated_last_frame_timestamp_ = media::kNoTimestamp(); |
623 } | 624 } |
624 | 625 |
625 } // namespace media | 626 } // namespace media |
OLD | NEW |