| 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/base/video_frame.h" | 5 #include "media/base/video_frame.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 21 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
| 22 VideoFrame::Format format, | 22 VideoFrame::Format format, |
| 23 const gfx::Size& coded_size, | 23 const gfx::Size& coded_size, |
| 24 const gfx::Rect& visible_rect, | 24 const gfx::Rect& visible_rect, |
| 25 const gfx::Size& natural_size, | 25 const gfx::Size& natural_size, |
| 26 base::TimeDelta timestamp) { | 26 base::TimeDelta timestamp) { |
| 27 DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size)); | 27 DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size)); |
| 28 scoped_refptr<VideoFrame> frame(new VideoFrame( | 28 scoped_refptr<VideoFrame> frame(new VideoFrame( |
| 29 format, coded_size, visible_rect, natural_size, timestamp)); | 29 format, coded_size, visible_rect, natural_size, timestamp)); |
| 30 switch (format) { | 30 switch (format) { |
| 31 case VideoFrame::RGB32: | |
| 32 frame->AllocateRGB(4u); | |
| 33 break; | |
| 34 case VideoFrame::YV12: | 31 case VideoFrame::YV12: |
| 35 case VideoFrame::YV12A: | 32 case VideoFrame::YV12A: |
| 36 case VideoFrame::YV16: | 33 case VideoFrame::YV16: |
| 37 case VideoFrame::I420: | 34 case VideoFrame::I420: |
| 38 frame->AllocateYUV(); | 35 frame->AllocateYUV(); |
| 39 break; | 36 break; |
| 40 default: | 37 default: |
| 41 LOG(FATAL) << "Unsupported frame format: " << format; | 38 LOG(FATAL) << "Unsupported frame format: " << format; |
| 42 } | 39 } |
| 43 return frame; | 40 return frame; |
| 44 } | 41 } |
| 45 | 42 |
| 46 // static | 43 // static |
| 47 std::string VideoFrame::FormatToString(VideoFrame::Format format) { | 44 std::string VideoFrame::FormatToString(VideoFrame::Format format) { |
| 48 switch (format) { | 45 switch (format) { |
| 49 case VideoFrame::UNKNOWN: | 46 case VideoFrame::UNKNOWN: |
| 50 return "UNKNOWN"; | 47 return "UNKNOWN"; |
| 51 case VideoFrame::RGB32: | |
| 52 return "RGB32"; | |
| 53 case VideoFrame::YV12: | 48 case VideoFrame::YV12: |
| 54 return "YV12"; | 49 return "YV12"; |
| 55 case VideoFrame::YV16: | 50 case VideoFrame::YV16: |
| 56 return "YV16"; | 51 return "YV16"; |
| 57 case VideoFrame::EMPTY: | 52 case VideoFrame::EMPTY: |
| 58 return "EMPTY"; | 53 return "EMPTY"; |
| 59 case VideoFrame::I420: | 54 case VideoFrame::I420: |
| 60 return "I420"; | 55 return "I420"; |
| 61 case VideoFrame::NATIVE_TEXTURE: | 56 case VideoFrame::NATIVE_TEXTURE: |
| 62 return "NATIVE_TEXTURE"; | 57 return "NATIVE_TEXTURE"; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 #endif | 219 #endif |
| 225 | 220 |
| 226 // static | 221 // static |
| 227 size_t VideoFrame::NumPlanes(Format format) { | 222 size_t VideoFrame::NumPlanes(Format format) { |
| 228 switch (format) { | 223 switch (format) { |
| 229 case VideoFrame::NATIVE_TEXTURE: | 224 case VideoFrame::NATIVE_TEXTURE: |
| 230 #if defined(GOOGLE_TV) | 225 #if defined(GOOGLE_TV) |
| 231 case VideoFrame::HOLE: | 226 case VideoFrame::HOLE: |
| 232 #endif | 227 #endif |
| 233 return 0; | 228 return 0; |
| 234 case VideoFrame::RGB32: | |
| 235 return 1; | |
| 236 case VideoFrame::YV12: | 229 case VideoFrame::YV12: |
| 237 case VideoFrame::YV16: | 230 case VideoFrame::YV16: |
| 238 case VideoFrame::I420: | 231 case VideoFrame::I420: |
| 239 return 3; | 232 return 3; |
| 240 case VideoFrame::YV12A: | 233 case VideoFrame::YV12A: |
| 241 return 4; | 234 return 4; |
| 242 case VideoFrame::EMPTY: | 235 case VideoFrame::EMPTY: |
| 243 case VideoFrame::UNKNOWN: | 236 case VideoFrame::UNKNOWN: |
| 244 break; | 237 break; |
| 245 } | 238 } |
| 246 NOTREACHED() << "Unsupported video frame format: " << format; | 239 NOTREACHED() << "Unsupported video frame format: " << format; |
| 247 return 0; | 240 return 0; |
| 248 } | 241 } |
| 249 | 242 |
| 250 static inline size_t RoundUp(size_t value, size_t alignment) { | 243 static inline size_t RoundUp(size_t value, size_t alignment) { |
| 251 // Check that |alignment| is a power of 2. | 244 // Check that |alignment| is a power of 2. |
| 252 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | 245 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
| 253 return ((value + (alignment - 1)) & ~(alignment-1)); | 246 return ((value + (alignment - 1)) & ~(alignment-1)); |
| 254 } | 247 } |
| 255 | 248 |
| 256 // static | 249 // static |
| 257 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) { | 250 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) { |
| 258 switch (format) { | 251 switch (format) { |
| 259 case VideoFrame::RGB32: | |
| 260 return coded_size.GetArea() * 4; | |
| 261 case VideoFrame::YV12: | 252 case VideoFrame::YV12: |
| 262 case VideoFrame::I420: { | 253 case VideoFrame::I420: { |
| 263 const size_t rounded_size = | 254 const size_t rounded_size = |
| 264 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); | 255 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); |
| 265 return rounded_size * 3 / 2; | 256 return rounded_size * 3 / 2; |
| 266 } | 257 } |
| 267 case VideoFrame::YV12A: { | 258 case VideoFrame::YV12A: { |
| 268 const size_t rounded_size = | 259 const size_t rounded_size = |
| 269 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); | 260 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); |
| 270 return rounded_size * 5 / 2; | 261 return rounded_size * 5 / 2; |
| 271 } | 262 } |
| 272 case VideoFrame::YV16: { | 263 case VideoFrame::YV16: { |
| 273 const size_t rounded_size = | 264 const size_t rounded_size = |
| 274 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); | 265 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); |
| 275 return rounded_size * 2; | 266 return rounded_size * 2; |
| 276 } | 267 } |
| 277 case VideoFrame::UNKNOWN: | 268 case VideoFrame::UNKNOWN: |
| 278 case VideoFrame::EMPTY: | 269 case VideoFrame::EMPTY: |
| 279 case VideoFrame::NATIVE_TEXTURE: | 270 case VideoFrame::NATIVE_TEXTURE: |
| 280 #if defined(GOOGLE_TV) | 271 #if defined(GOOGLE_TV) |
| 281 case VideoFrame::HOLE: | 272 case VideoFrame::HOLE: |
| 282 #endif | 273 #endif |
| 283 break; | 274 break; |
| 284 } | 275 } |
| 285 NOTREACHED() << "Unsupported video frame format: " << format; | 276 NOTREACHED() << "Unsupported video frame format: " << format; |
| 286 return 0; | 277 return 0; |
| 287 } | 278 } |
| 288 | 279 |
| 289 // Release data allocated by AllocateRGB() or AllocateYUV(). | 280 // Release data allocated by AllocateYUV(). |
| 290 static void ReleaseData(uint8* data) { | 281 static void ReleaseData(uint8* data) { |
| 291 DCHECK(data); | 282 DCHECK(data); |
| 292 base::AlignedFree(data); | 283 base::AlignedFree(data); |
| 293 } | 284 } |
| 294 | 285 |
| 295 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { | |
| 296 // Round up to align at least at a 16-byte boundary for each row. | |
| 297 // This is sufficient for MMX and SSE2 reads (movq/movdqa). | |
| 298 size_t bytes_per_row = RoundUp(coded_size_.width(), | |
| 299 kFrameSizeAlignment) * bytes_per_pixel; | |
| 300 size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment); | |
| 301 strides_[VideoFrame::kRGBPlane] = bytes_per_row; | |
| 302 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>( | |
| 303 base::AlignedAlloc(bytes_per_row * aligned_height + kFrameSizePadding, | |
| 304 kFrameAddressAlignment)); | |
| 305 no_longer_needed_cb_ = base::Bind(&ReleaseData, data_[VideoFrame::kRGBPlane]); | |
| 306 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); | |
| 307 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); | |
| 308 } | |
| 309 | |
| 310 void VideoFrame::AllocateYUV() { | 286 void VideoFrame::AllocateYUV() { |
| 311 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || | 287 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || |
| 312 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420); | 288 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420); |
| 313 // Align Y rows at least at 16 byte boundaries. The stride for both | 289 // Align Y rows at least at 16 byte boundaries. The stride for both |
| 314 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for | 290 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for |
| 315 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in | 291 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in |
| 316 // the case of YV12 the strides are identical for the same width surface, but | 292 // the case of YV12 the strides are identical for the same width surface, but |
| 317 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as | 293 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as |
| 318 // YV16. We also round the height of the surface allocated to be an even | 294 // YV16. We also round the height of the surface allocated to be an even |
| 319 // number to avoid any potential of faulting by code that attempts to access | 295 // number to avoid any potential of faulting by code that attempts to access |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 | 363 |
| 388 int VideoFrame::stride(size_t plane) const { | 364 int VideoFrame::stride(size_t plane) const { |
| 389 DCHECK(IsValidPlane(plane)); | 365 DCHECK(IsValidPlane(plane)); |
| 390 return strides_[plane]; | 366 return strides_[plane]; |
| 391 } | 367 } |
| 392 | 368 |
| 393 int VideoFrame::row_bytes(size_t plane) const { | 369 int VideoFrame::row_bytes(size_t plane) const { |
| 394 DCHECK(IsValidPlane(plane)); | 370 DCHECK(IsValidPlane(plane)); |
| 395 int width = coded_size_.width(); | 371 int width = coded_size_.width(); |
| 396 switch (format_) { | 372 switch (format_) { |
| 397 // 32bpp. | |
| 398 case RGB32: | |
| 399 return width * 4; | |
| 400 | |
| 401 // Planar, 8bpp. | 373 // Planar, 8bpp. |
| 402 case YV12A: | 374 case YV12A: |
| 403 if (plane == kAPlane) | 375 if (plane == kAPlane) |
| 404 return width; | 376 return width; |
| 405 // Fallthrough. | 377 // Fallthrough. |
| 406 case YV12: | 378 case YV12: |
| 407 case YV16: | 379 case YV16: |
| 408 case I420: | 380 case I420: |
| 409 if (plane == kYPlane) | 381 if (plane == kYPlane) |
| 410 return width; | 382 return width; |
| 411 return RoundUp(width, 2) / 2; | 383 return RoundUp(width, 2) / 2; |
| 412 | 384 |
| 413 default: | 385 default: |
| 414 break; | 386 break; |
| 415 } | 387 } |
| 416 | 388 |
| 417 // Intentionally leave out non-production formats. | 389 // Intentionally leave out non-production formats. |
| 418 NOTREACHED() << "Unsupported video frame format: " << format_; | 390 NOTREACHED() << "Unsupported video frame format: " << format_; |
| 419 return 0; | 391 return 0; |
| 420 } | 392 } |
| 421 | 393 |
| 422 int VideoFrame::rows(size_t plane) const { | 394 int VideoFrame::rows(size_t plane) const { |
| 423 DCHECK(IsValidPlane(plane)); | 395 DCHECK(IsValidPlane(plane)); |
| 424 int height = coded_size_.height(); | 396 int height = coded_size_.height(); |
| 425 switch (format_) { | 397 switch (format_) { |
| 426 case RGB32: | |
| 427 case YV16: | 398 case YV16: |
| 428 return height; | 399 return height; |
| 429 | 400 |
| 430 case YV12A: | 401 case YV12A: |
| 431 if (plane == kAPlane) | 402 if (plane == kAPlane) |
| 432 return height; | 403 return height; |
| 433 // Fallthrough. | 404 // Fallthrough. |
| 434 case YV12: | 405 case YV12: |
| 435 case I420: | 406 case I420: |
| 436 if (plane == kYPlane) | 407 if (plane == kYPlane) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 : mailbox_(mailbox), | 460 : mailbox_(mailbox), |
| 490 sync_point_(sync_point), | 461 sync_point_(sync_point), |
| 491 release_callback_(release_callback) {} | 462 release_callback_(release_callback) {} |
| 492 | 463 |
| 493 VideoFrame::MailboxHolder::~MailboxHolder() { | 464 VideoFrame::MailboxHolder::~MailboxHolder() { |
| 494 if (!release_callback_.is_null()) | 465 if (!release_callback_.is_null()) |
| 495 release_callback_.Run(sync_point_); | 466 release_callback_.Run(sync_point_); |
| 496 } | 467 } |
| 497 | 468 |
| 498 } // namespace media | 469 } // namespace media |
| OLD | NEW |