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 3 // found in the LICENSE file. 4 5 #include "media/base/video_frame.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/callback_helpers.h" 11 #include "base/logging.h" 12 #include "base/memory/aligned_memory.h" 13 #include "base/strings/string_piece.h" 14 #include "gpu/command_buffer/common/mailbox_holder.h" 15 #include "media/base/limits.h" 16 #include "media/base/video_util.h" 17 18 #if !defined(MEDIA_FOR_CAST_IOS) 19 #include "third_party/skia/include/core/SkBitmap.h" 20 #endif 21 22 namespace media { 23 24 static inline size_t RoundUp(size_t value, size_t alignment) { 25 // Check that |alignment| is a power of 2. 26 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); 27 return ((value + (alignment - 1)) & ~(alignment - 1)); 28 } 29 30 // Rounds up |coded_size| if necessary for |format|. 31 static gfx::Size AdjustCodedSize(VideoFrame::Format format, 32 const gfx::Size& coded_size) { 33 gfx::Size new_coded_size(coded_size); 34 switch (format) { 35 case VideoFrame::YV12: 36 case VideoFrame::YV12A: 37 case VideoFrame::I420: 38 case VideoFrame::YV12J: 39 new_coded_size.set_height(RoundUp(new_coded_size.height(), 2)); 40 // Fallthrough. 41 case VideoFrame::YV16: 42 new_coded_size.set_width(RoundUp(new_coded_size.width(), 2)); 43 break; 44 default: 45 break; 46 } 47 return new_coded_size; 48 } 49 50 // static 51 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( 52 VideoFrame::Format format, 53 const gfx::Size& coded_size, 54 const gfx::Rect& visible_rect, 55 const gfx::Size& natural_size, 56 base::TimeDelta timestamp) { 57 DCHECK(format != VideoFrame::UNKNOWN && 58 format != VideoFrame::NV12 && 59 format != VideoFrame::NATIVE_TEXTURE); 60 #if defined(VIDEO_HOLE) 61 DCHECK(format != VideoFrame::HOLE); 62 #endif // defined(VIDEO_HOLE) 63 64 // Since we're creating a new YUV frame (and allocating memory for it 65 // ourselves), we can pad the requested |coded_size| if necessary if the 66 // request does not line up on sample boundaries. 67 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); 68 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); 69 70 scoped_refptr<VideoFrame> frame( 71 new VideoFrame(format, 72 new_coded_size, 73 visible_rect, 74 natural_size, 75 scoped_ptr<gpu::MailboxHolder>(), 76 timestamp, 77 false)); 78 frame->AllocateYUV(); 79 return frame; 80 } 81 82 // static 83 std::string VideoFrame::FormatToString(VideoFrame::Format format) { 84 switch (format) { 85 case VideoFrame::UNKNOWN: 86 return "UNKNOWN"; 87 case VideoFrame::YV12: 88 return "YV12"; 89 case VideoFrame::YV16: 90 return "YV16"; 91 case VideoFrame::I420: 92 return "I420"; 93 case VideoFrame::NATIVE_TEXTURE: 94 return "NATIVE_TEXTURE"; 95 #if defined(VIDEO_HOLE) 96 case VideoFrame::HOLE: 97 return "HOLE"; 98 #endif // defined(VIDEO_HOLE) 99 case VideoFrame::YV12A: 100 return "YV12A"; 101 case VideoFrame::YV12J: 102 return "YV12J"; 103 case VideoFrame::NV12: 104 return "NV12"; 105 case VideoFrame::YV24: 106 return "YV24"; 107 } 108 NOTREACHED() << "Invalid videoframe format provided: " << format; 109 return ""; 110 } 111 112 // static 113 bool VideoFrame::IsValidConfig(VideoFrame::Format format, 114 const gfx::Size& coded_size, 115 const gfx::Rect& visible_rect, 116 const gfx::Size& natural_size) { 117 // Check maximum limits for all formats. 118 if (coded_size.GetArea() > limits::kMaxCanvas || 119 coded_size.width() > limits::kMaxDimension || 120 coded_size.height() > limits::kMaxDimension || 121 visible_rect.x() < 0 || visible_rect.y() < 0 || 122 visible_rect.right() > coded_size.width() || 123 visible_rect.bottom() > coded_size.height() || 124 natural_size.GetArea() > limits::kMaxCanvas || 125 natural_size.width() > limits::kMaxDimension || 126 natural_size.height() > limits::kMaxDimension) 127 return false; 128 129 // Check format-specific width/height requirements. 130 switch (format) { 131 case VideoFrame::UNKNOWN: 132 return (coded_size.IsEmpty() && visible_rect.IsEmpty() && 133 natural_size.IsEmpty()); 134 case VideoFrame::YV24: 135 break; 136 case VideoFrame::YV12: 137 case VideoFrame::YV12J: 138 case VideoFrame::I420: 139 case VideoFrame::YV12A: 140 case VideoFrame::NV12: 141 // Subsampled YUV formats have width/height requirements. 142 if (static_cast<size_t>(coded_size.height()) < 143 RoundUp(visible_rect.bottom(), 2)) 144 return false; 145 // Fallthrough. 146 case VideoFrame::YV16: 147 if (static_cast<size_t>(coded_size.width()) < 148 RoundUp(visible_rect.right(), 2)) 149 return false; 150 break; 151 case VideoFrame::NATIVE_TEXTURE: 152 #if defined(VIDEO_HOLE) 153 case VideoFrame::HOLE: 154 #endif // defined(VIDEO_HOLE) 155 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are 156 // allowed to skip the below check and be empty. 157 return true; 158 } 159 160 // Check that software-allocated buffer formats are not empty. 161 return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() && 162 !natural_size.IsEmpty()); 163 } 164 165 // static 166 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( 167 scoped_ptr<gpu::MailboxHolder> mailbox_holder, 168 const ReleaseMailboxCB& mailbox_holder_release_cb, 169 const gfx::Size& coded_size, 170 const gfx::Rect& visible_rect, 171 const gfx::Size& natural_size, 172 base::TimeDelta timestamp, 173 const ReadPixelsCB& read_pixels_cb) { 174 scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE, 175 coded_size, 176 visible_rect, 177 natural_size, 178 mailbox_holder.Pass(), 179 timestamp, 180 false)); 181 frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb; 182 frame->read_pixels_cb_ = read_pixels_cb; 183 184 return frame; 185 } 186 187 #if !defined(MEDIA_FOR_CAST_IOS) 188 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) { 189 DCHECK_EQ(format_, NATIVE_TEXTURE); 190 if (!read_pixels_cb_.is_null()) 191 read_pixels_cb_.Run(pixels); 192 } 193 #endif 194 195 // static 196 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory( 197 Format format, 198 const gfx::Size& coded_size, 199 const gfx::Rect& visible_rect, 200 const gfx::Size& natural_size, 201 uint8* data, 202 size_t data_size, 203 base::SharedMemoryHandle handle, 204 base::TimeDelta timestamp, 205 const base::Closure& no_longer_needed_cb) { 206 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); 207 208 if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size)) 209 return NULL; 210 if (data_size < AllocationSize(format, new_coded_size)) 211 return NULL; 212 213 switch (format) { 214 case VideoFrame::I420: { 215 scoped_refptr<VideoFrame> frame( 216 new VideoFrame(format, 217 new_coded_size, 218 visible_rect, 219 natural_size, 220 scoped_ptr<gpu::MailboxHolder>(), 221 timestamp, 222 false)); 223 frame->shared_memory_handle_ = handle; 224 frame->strides_[kYPlane] = new_coded_size.width(); 225 frame->strides_[kUPlane] = new_coded_size.width() / 2; 226 frame->strides_[kVPlane] = new_coded_size.width() / 2; 227 frame->data_[kYPlane] = data; 228 frame->data_[kUPlane] = data + new_coded_size.GetArea(); 229 frame->data_[kVPlane] = data + (new_coded_size.GetArea() * 5 / 4); 230 frame->no_longer_needed_cb_ = no_longer_needed_cb; 231 return frame; 232 } 233 default: 234 NOTIMPLEMENTED(); 235 return NULL; 236 } 237 } 238 239 #if defined(OS_POSIX) 240 // static 241 scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs( 242 Format format, 243 const gfx::Size& coded_size, 244 const gfx::Rect& visible_rect, 245 const gfx::Size& natural_size, 246 const std::vector<int> dmabuf_fds, 247 base::TimeDelta timestamp, 248 const base::Closure& no_longer_needed_cb) { 249 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) 250 return NULL; 251 252 if (dmabuf_fds.size() != NumPlanes(format)) { 253 LOG(FATAL) << "Not enough dmabuf fds provided!"; 254 return NULL; 255 } 256 257 scoped_refptr<VideoFrame> frame( 258 new VideoFrame(format, 259 coded_size, 260 visible_rect, 261 natural_size, 262 scoped_ptr<gpu::MailboxHolder>(), 263 timestamp, 264 false)); 265 266 for (size_t i = 0; i < dmabuf_fds.size(); ++i) { 267 int duped_fd = HANDLE_EINTR(dup(dmabuf_fds[i])); 268 if (duped_fd == -1) { 269 // The already-duped in previous iterations fds will be closed when 270 // the partially-created frame drops out of scope here. 271 DLOG(ERROR) << "Failed duplicating a dmabuf fd"; 272 return NULL; 273 } 274 275 frame->dmabuf_fds_[i].reset(duped_fd); 276 // Data is accessible only via fds. 277 frame->data_[i] = NULL; 278 frame->strides_[i] = 0; 279 } 280 281 frame->no_longer_needed_cb_ = no_longer_needed_cb; 282 return frame; 283 } 284 #endif 285 286 #if defined(OS_MACOSX) 287 // static 288 scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer( 289 CVPixelBufferRef cv_pixel_buffer, 290 base::TimeDelta timestamp) { 291 DCHECK(cv_pixel_buffer); 292 DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID()); 293 294 OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer); 295 Format format; 296 // There are very few compatible CV pixel formats, so just check each. 297 if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) { 298 format = Format::I420; 299 } else if (cv_format == kCVPixelFormatType_444YpCbCr8) { 300 format = Format::YV24; 301 } else if (cv_format == '420v') { 302 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the 303 // minimum OS X and iOS SDKs permits it. 304 format = Format::NV12; 305 } else { 306 DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format; 307 return NULL; 308 } 309 310 gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer)); 311 gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer)); 312 gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer)); 313 314 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) 315 return NULL; 316 317 scoped_refptr<VideoFrame> frame( 318 new VideoFrame(format, 319 coded_size, 320 visible_rect, 321 natural_size, 322 scoped_ptr<gpu::MailboxHolder>(), 323 timestamp, 324 false)); 325 326 frame->cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN); 327 return frame; 328 } 329 #endif 330 331 // static 332 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData( 333 Format format, 334 const gfx::Size& coded_size, 335 const gfx::Rect& visible_rect, 336 const gfx::Size& natural_size, 337 int32 y_stride, 338 int32 u_stride, 339 int32 v_stride, 340 uint8* y_data, 341 uint8* u_data, 342 uint8* v_data, 343 base::TimeDelta timestamp, 344 const base::Closure& no_longer_needed_cb) { 345 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); 346 CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); 347 348 scoped_refptr<VideoFrame> frame( 349 new VideoFrame(format, 350 new_coded_size, 351 visible_rect, 352 natural_size, 353 scoped_ptr<gpu::MailboxHolder>(), 354 timestamp, 355 false)); 356 frame->strides_[kYPlane] = y_stride; 357 frame->strides_[kUPlane] = u_stride; 358 frame->strides_[kVPlane] = v_stride; 359 frame->data_[kYPlane] = y_data; 360 frame->data_[kUPlane] = u_data; 361 frame->data_[kVPlane] = v_data; 362 frame->no_longer_needed_cb_ = no_longer_needed_cb; 363 return frame; 364 } 365 366 // static 367 scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame( 368 const scoped_refptr<VideoFrame>& frame, 369 const gfx::Rect& visible_rect, 370 const gfx::Size& natural_size, 371 const base::Closure& no_longer_needed_cb) { 372 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support 373 // for that here yet, see http://crbug/362521. 374 CHECK_NE(frame->format(), NATIVE_TEXTURE); 375 376 DCHECK(frame->visible_rect().Contains(visible_rect)); 377 scoped_refptr<VideoFrame> wrapped_frame( 378 new VideoFrame(frame->format(), 379 frame->coded_size(), 380 visible_rect, 381 natural_size, 382 scoped_ptr<gpu::MailboxHolder>(), 383 frame->timestamp(), 384 frame->end_of_stream())); 385 386 for (size_t i = 0; i < NumPlanes(frame->format()); ++i) { 387 wrapped_frame->strides_[i] = frame->stride(i); 388 wrapped_frame->data_[i] = frame->data(i); 389 } 390 391 wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb; 392 return wrapped_frame; 393 } 394 395 // static 396 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() { 397 return new VideoFrame(VideoFrame::UNKNOWN, 398 gfx::Size(), 399 gfx::Rect(), 400 gfx::Size(), 401 scoped_ptr<gpu::MailboxHolder>(), 402 kNoTimestamp(), 403 true); 404 } 405 406 // static 407 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame( 408 const gfx::Size& size, 409 uint8 y, uint8 u, uint8 v, 410 base::TimeDelta timestamp) { 411 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( 412 VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); 413 FillYUV(frame.get(), y, u, v); 414 return frame; 415 } 416 417 // static 418 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) { 419 const uint8 kBlackY = 0x00; 420 const uint8 kBlackUV = 0x80; 421 const base::TimeDelta kZero; 422 return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero); 423 } 424 425 // static 426 scoped_refptr<VideoFrame> VideoFrame::CreateTransparentFrame( 427 const gfx::Size& size) { 428 const uint8 kBlackY = 0x00; 429 const uint8 kBlackUV = 0x00; 430 const uint8 kTransparentA = 0x00; 431 const base::TimeDelta kZero; 432 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( 433 VideoFrame::YV12A, size, gfx::Rect(size), size, kZero); 434 FillYUVA(frame.get(), kBlackY, kBlackUV, kBlackUV, kTransparentA); 435 return frame; 436 } 437 438 #if defined(VIDEO_HOLE) 439 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not 440 // maintained by the general compositor team. Please contact the following 441 // people instead: 442 // 443 // wonsik (at) chromium.org 444 // ycheo (at) chromium.org 445 446 // static 447 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame( 448 const gfx::Size& size) { 449 DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size)); 450 scoped_refptr<VideoFrame> frame( 451 new VideoFrame(VideoFrame::HOLE, 452 size, 453 gfx::Rect(size), 454 size, 455 scoped_ptr<gpu::MailboxHolder>(), 456 base::TimeDelta(), 457 false)); 458 return frame; 459 } 460 #endif // defined(VIDEO_HOLE) 461 462 // static 463 size_t VideoFrame::NumPlanes(Format format) { 464 switch (format) { 465 case VideoFrame::NATIVE_TEXTURE: 466 #if defined(VIDEO_HOLE) 467 case VideoFrame::HOLE: 468 #endif // defined(VIDEO_HOLE) 469 return 0; 470 case VideoFrame::NV12: 471 return 2; 472 case VideoFrame::YV12: 473 case VideoFrame::YV16: 474 case VideoFrame::I420: 475 case VideoFrame::YV12J: 476 case VideoFrame::YV24: 477 return 3; 478 case VideoFrame::YV12A: 479 return 4; 480 case VideoFrame::UNKNOWN: 481 break; 482 } 483 NOTREACHED() << "Unsupported video frame format: " << format; 484 return 0; 485 } 486 487 488 // static 489 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) { 490 size_t total = 0; 491 for (size_t i = 0; i < NumPlanes(format); ++i) 492 total += PlaneAllocationSize(format, i, coded_size); 493 return total; 494 } 495 496 // static 497 gfx::Size VideoFrame::PlaneSize(Format format, 498 size_t plane, 499 const gfx::Size& coded_size) { 500 // Align to multiple-of-two size overall. This ensures that non-subsampled 501 // planes can be addressed by pixel with the same scaling as the subsampled 502 // planes. 503 const int width = RoundUp(coded_size.width(), 2); 504 const int height = RoundUp(coded_size.height(), 2); 505 switch (format) { 506 case VideoFrame::YV24: 507 switch (plane) { 508 case VideoFrame::kYPlane: 509 case VideoFrame::kUPlane: 510 case VideoFrame::kVPlane: 511 return gfx::Size(width, height); 512 default: 513 break; 514 } 515 break; 516 case VideoFrame::YV12: 517 case VideoFrame::YV12J: 518 case VideoFrame::I420: 519 switch (plane) { 520 case VideoFrame::kYPlane: 521 return gfx::Size(width, height); 522 case VideoFrame::kUPlane: 523 case VideoFrame::kVPlane: 524 return gfx::Size(width / 2, height / 2); 525 default: 526 break; 527 } 528 break; 529 case VideoFrame::YV12A: 530 switch (plane) { 531 case VideoFrame::kYPlane: 532 case VideoFrame::kAPlane: 533 return gfx::Size(width, height); 534 case VideoFrame::kUPlane: 535 case VideoFrame::kVPlane: 536 return gfx::Size(width / 2, height / 2); 537 default: 538 break; 539 } 540 break; 541 case VideoFrame::YV16: 542 switch (plane) { 543 case VideoFrame::kYPlane: 544 return gfx::Size(width, height); 545 case VideoFrame::kUPlane: 546 case VideoFrame::kVPlane: 547 return gfx::Size(width / 2, height); 548 default: 549 break; 550 } 551 break; 552 case VideoFrame::NV12: 553 switch (plane) { 554 case VideoFrame::kYPlane: 555 return gfx::Size(width, height); 556 case VideoFrame::kUVPlane: 557 return gfx::Size(width, height / 2); 558 default: 559 break; 560 } 561 break; 562 case VideoFrame::UNKNOWN: 563 case VideoFrame::NATIVE_TEXTURE: 564 #if defined(VIDEO_HOLE) 565 case VideoFrame::HOLE: 566 #endif // defined(VIDEO_HOLE) 567 break; 568 } 569 NOTREACHED() << "Unsupported video frame format/plane: " 570 << format << "/" << plane; 571 return gfx::Size(); 572 } 573 574 size_t VideoFrame::PlaneAllocationSize(Format format, 575 size_t plane, 576 const gfx::Size& coded_size) { 577 // VideoFrame formats are (so far) all YUV and 1 byte per sample. 578 return PlaneSize(format, plane, coded_size).GetArea(); 579 } 580 581 // static 582 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) { 583 switch (format) { 584 case VideoFrame::YV24: 585 switch (plane) { 586 case kYPlane: 587 case kUPlane: 588 case kVPlane: 589 return 8; 590 default: 591 break; 592 } 593 break; 594 case VideoFrame::YV12: 595 case VideoFrame::YV16: 596 case VideoFrame::I420: 597 case VideoFrame::YV12J: 598 switch (plane) { 599 case kYPlane: 600 return 8; 601 case kUPlane: 602 case kVPlane: 603 return 2; 604 default: 605 break; 606 } 607 break; 608 case VideoFrame::YV12A: 609 switch (plane) { 610 case kYPlane: 611 case kAPlane: 612 return 8; 613 case kUPlane: 614 case kVPlane: 615 return 2; 616 default: 617 break; 618 } 619 break; 620 case VideoFrame::NV12: 621 switch (plane) { 622 case kYPlane: 623 return 8; 624 case kUVPlane: 625 return 4; 626 default: 627 break; 628 } 629 break; 630 case VideoFrame::UNKNOWN: 631 #if defined(VIDEO_HOLE) 632 case VideoFrame::HOLE: 633 #endif // defined(VIDEO_HOLE) 634 case VideoFrame::NATIVE_TEXTURE: 635 break; 636 } 637 NOTREACHED() << "Unsupported video frame format/plane: " 638 << format << "/" << plane; 639 return 0; 640 } 641 642 // Release data allocated by AllocateYUV(). 643 static void ReleaseData(uint8* data) { 644 DCHECK(data); 645 base::AlignedFree(data); 646 } 647 648 void VideoFrame::AllocateYUV() { 649 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || 650 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 || 651 format_ == VideoFrame::YV12J || format_ == VideoFrame::YV24); 652 // Align Y rows at least at 16 byte boundaries. The stride for both 653 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for 654 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in 655 // the case of YV12 the strides are identical for the same width surface, but 656 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as 657 // YV16. We also round the height of the surface allocated to be an even 658 // number to avoid any potential of faulting by code that attempts to access 659 // the Y values of the final row, but assumes that the last row of U & V 660 // applies to a full two rows of Y. YV12A is the same as YV12, but with an 661 // additional alpha plane that has the same size and alignment as the Y plane. 662 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 663 kFrameSizeAlignment); 664 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 665 kFrameSizeAlignment); 666 667 // The *2 here is because some formats (e.g. h264) allow interlaced coding, 668 // and then the size needs to be a multiple of two macroblocks (vertically). 669 // See libavcodec/utils.c:avcodec_align_dimensions2(). 670 size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); 671 size_t uv_height = 672 (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A || 673 format_ == VideoFrame::I420) 674 ? y_height / 2 675 : y_height; 676 size_t y_bytes = y_height * y_stride; 677 size_t uv_bytes = uv_height * uv_stride; 678 size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0; 679 680 // The extra line of UV being allocated is because h264 chroma MC 681 // overreads by one line in some cases, see libavcodec/utils.c: 682 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: 683 // put_h264_chroma_mc4_ssse3(). 684 const size_t data_size = 685 y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding; 686 uint8* data = reinterpret_cast<uint8*>( 687 base::AlignedAlloc(data_size, kFrameAddressAlignment)); 688 // FFmpeg expects the initialize allocation to be zero-initialized. Failure 689 // to do so can lead to unitialized value usage. See http://crbug.com/390941 690 memset(data, 0, data_size); 691 no_longer_needed_cb_ = base::Bind(&ReleaseData, data); 692 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); 693 data_[VideoFrame::kYPlane] = data; 694 data_[VideoFrame::kUPlane] = data + y_bytes; 695 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; 696 strides_[VideoFrame::kYPlane] = y_stride; 697 strides_[VideoFrame::kUPlane] = uv_stride; 698 strides_[VideoFrame::kVPlane] = uv_stride; 699 if (format_ == YV12A) { 700 data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes); 701 strides_[VideoFrame::kAPlane] = y_stride; 702 } 703 } 704 705 VideoFrame::VideoFrame(VideoFrame::Format format, 706 const gfx::Size& coded_size, 707 const gfx::Rect& visible_rect, 708 const gfx::Size& natural_size, 709 scoped_ptr<gpu::MailboxHolder> mailbox_holder, 710 base::TimeDelta timestamp, 711 bool end_of_stream) 712 : format_(format), 713 coded_size_(coded_size), 714 visible_rect_(visible_rect), 715 natural_size_(natural_size), 716 mailbox_holder_(mailbox_holder.Pass()), 717 shared_memory_handle_(base::SharedMemory::NULLHandle()), 718 timestamp_(timestamp), 719 release_sync_point_(0), 720 end_of_stream_(end_of_stream) { 721 DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_)); 722 723 memset(&strides_, 0, sizeof(strides_)); 724 memset(&data_, 0, sizeof(data_)); 725 } 726 727 VideoFrame::~VideoFrame() { 728 if (!mailbox_holder_release_cb_.is_null()) { 729 uint32 release_sync_point; 730 { 731 // To ensure that changes to |release_sync_point_| are visible on this 732 // thread (imply a memory barrier). 733 base::AutoLock locker(release_sync_point_lock_); 734 release_sync_point = release_sync_point_; 735 } 736 base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_point); 737 } 738 if (!no_longer_needed_cb_.is_null()) 739 base::ResetAndReturn(&no_longer_needed_cb_).Run(); 740 } 741 742 // static 743 bool VideoFrame::IsValidPlane(size_t plane, VideoFrame::Format format) { 744 return (plane < NumPlanes(format)); 745 } 746 747 int VideoFrame::stride(size_t plane) const { 748 DCHECK(IsValidPlane(plane, format_)); 749 return strides_[plane]; 750 } 751 752 // static 753 size_t VideoFrame::RowBytes(size_t plane, VideoFrame::Format format, 754 int width) { 755 DCHECK(IsValidPlane(plane, format)); 756 switch (format) { 757 case VideoFrame::YV24: 758 switch (plane) { 759 case kYPlane: 760 case kUPlane: 761 case kVPlane: 762 return width; 763 default: 764 break; 765 } 766 break; 767 case VideoFrame::YV12: 768 case VideoFrame::YV16: 769 case VideoFrame::I420: 770 case VideoFrame::YV12J: 771 switch (plane) { 772 case kYPlane: 773 return width; 774 case kUPlane: 775 case kVPlane: 776 return RoundUp(width, 2) / 2; 777 default: 778 break; 779 } 780 break; 781 case VideoFrame::YV12A: 782 switch (plane) { 783 case kYPlane: 784 case kAPlane: 785 return width; 786 case kUPlane: 787 case kVPlane: 788 return RoundUp(width, 2) / 2; 789 default: 790 break; 791 } 792 break; 793 case VideoFrame::NV12: 794 switch (plane) { 795 case kYPlane: 796 case kUVPlane: 797 return width; 798 default: 799 break; 800 } 801 break; 802 case VideoFrame::UNKNOWN: 803 #if defined(VIDEO_HOLE) 804 case VideoFrame::HOLE: 805 #endif // defined(VIDEO_HOLE) 806 case VideoFrame::NATIVE_TEXTURE: 807 break; 808 } 809 NOTREACHED() << "Unsupported video frame format/plane: " << format << "/" 810 << plane; 811 return 0; 812 } 813 814 int VideoFrame::row_bytes(size_t plane) const { 815 return RowBytes(plane, format_, coded_size_.width()); 816 } 817 818 // static 819 size_t VideoFrame::Rows(size_t plane, VideoFrame::Format format, int height) { 820 DCHECK(IsValidPlane(plane, format)); 821 switch (format) { 822 case VideoFrame::YV24: 823 case VideoFrame::YV16: 824 switch (plane) { 825 case kYPlane: 826 case kUPlane: 827 case kVPlane: 828 return height; 829 default: 830 break; 831 } 832 break; 833 case VideoFrame::YV12: 834 case VideoFrame::YV12J: 835 case VideoFrame::I420: 836 switch (plane) { 837 case kYPlane: 838 return height; 839 case kUPlane: 840 case kVPlane: 841 return RoundUp(height, 2) / 2; 842 default: 843 break; 844 } 845 break; 846 case VideoFrame::YV12A: 847 switch (plane) { 848 case kYPlane: 849 case kAPlane: 850 return height; 851 case kUPlane: 852 case kVPlane: 853 return RoundUp(height, 2) / 2; 854 default: 855 break; 856 } 857 break; 858 case VideoFrame::NV12: 859 switch (plane) { 860 case kYPlane: 861 return height; 862 case kUVPlane: 863 return RoundUp(height, 2) / 2; 864 default: 865 break; 866 } 867 break; 868 case VideoFrame::UNKNOWN: 869 #if defined(VIDEO_HOLE) 870 case VideoFrame::HOLE: 871 #endif // defined(VIDEO_HOLE) 872 case VideoFrame::NATIVE_TEXTURE: 873 break; 874 } 875 NOTREACHED() << "Unsupported video frame format/plane: " << format << "/" 876 << plane; 877 return 0; 878 } 879 880 int VideoFrame::rows(size_t plane) const { 881 return Rows(plane, format_, coded_size_.height()); 882 } 883 884 uint8* VideoFrame::data(size_t plane) const { 885 DCHECK(IsValidPlane(plane, format_)); 886 return data_[plane]; 887 } 888 889 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const { 890 DCHECK_EQ(format_, NATIVE_TEXTURE); 891 return mailbox_holder_.get(); 892 } 893 894 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const { 895 return shared_memory_handle_; 896 } 897 898 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) { 899 DCHECK_EQ(format_, NATIVE_TEXTURE); 900 base::AutoLock locker(release_sync_point_lock_); 901 // Must wait on the previous sync point before inserting a new sync point so 902 // that |mailbox_holder_release_cb_| guarantees the previous sync point 903 // occurred when it waits on |release_sync_point_|. 904 if (release_sync_point_) 905 client->WaitSyncPoint(release_sync_point_); 906 release_sync_point_ = client->InsertSyncPoint(); 907 } 908 909 #if defined(OS_POSIX) 910 int VideoFrame::dmabuf_fd(size_t plane) const { 911 return dmabuf_fds_[plane].get(); 912 } 913 #endif 914 915 #if defined(OS_MACOSX) 916 CVPixelBufferRef VideoFrame::cv_pixel_buffer() const { 917 return cv_pixel_buffer_.get(); 918 } 919 #endif 920 921 void VideoFrame::HashFrameForTesting(base::MD5Context* context) { 922 for (int plane = 0; plane < kMaxPlanes; ++plane) { 923 if (!IsValidPlane(plane, format_)) 924 break; 925 for (int row = 0; row < rows(plane); ++row) { 926 base::MD5Update(context, base::StringPiece( 927 reinterpret_cast<char*>(data(plane) + stride(plane) * row), 928 row_bytes(plane))); 929 } 930 } 931 } 932 933 } // namespace media 934