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