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