video_frame.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 21// static 22scoped_refptr<VideoFrame> VideoFrame::CreateFrame( 23 VideoFrame::Format format, 24 const gfx::Size& coded_size, 25 const gfx::Rect& visible_rect, 26 const gfx::Size& natural_size, 27 base::TimeDelta timestamp) { 28 DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size)); 29 scoped_refptr<VideoFrame> frame(new VideoFrame( 30 format, coded_size, visible_rect, natural_size, timestamp, false)); 31 switch (format) { 32 case VideoFrame::YV12: 33 case VideoFrame::YV12A: 34 case VideoFrame::YV16: 35 case VideoFrame::I420: 36 case VideoFrame::YV12J: 37 frame->AllocateYUV(); 38 break; 39 default: 40 LOG(FATAL) << "Unsupported frame format: " << format; 41 } 42 return frame; 43} 44 45// static 46std::string VideoFrame::FormatToString(VideoFrame::Format format) { 47 switch (format) { 48 case VideoFrame::UNKNOWN: 49 return "UNKNOWN"; 50 case VideoFrame::YV12: 51 return "YV12"; 52 case VideoFrame::YV16: 53 return "YV16"; 54 case VideoFrame::I420: 55 return "I420"; 56 case VideoFrame::NATIVE_TEXTURE: 57 return "NATIVE_TEXTURE"; 58#if defined(VIDEO_HOLE) 59 case VideoFrame::HOLE: 60 return "HOLE"; 61#endif // defined(VIDEO_HOLE) 62 case VideoFrame::YV12A: 63 return "YV12A"; 64 case VideoFrame::YV12J: 65 return "YV12J"; 66 } 67 NOTREACHED() << "Invalid videoframe format provided: " << format; 68 return ""; 69} 70 71// static 72bool VideoFrame::IsValidConfig(VideoFrame::Format format, 73 const gfx::Size& coded_size, 74 const gfx::Rect& visible_rect, 75 const gfx::Size& natural_size) { 76 return (format != VideoFrame::UNKNOWN && 77 !coded_size.IsEmpty() && 78 coded_size.GetArea() <= limits::kMaxCanvas && 79 coded_size.width() <= limits::kMaxDimension && 80 coded_size.height() <= limits::kMaxDimension && 81 !visible_rect.IsEmpty() && 82 visible_rect.x() >= 0 && visible_rect.y() >= 0 && 83 visible_rect.right() <= coded_size.width() && 84 visible_rect.bottom() <= coded_size.height() && 85 !natural_size.IsEmpty() && 86 natural_size.GetArea() <= limits::kMaxCanvas && 87 natural_size.width() <= limits::kMaxDimension && 88 natural_size.height() <= limits::kMaxDimension); 89} 90 91// static 92scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( 93 scoped_ptr<gpu::MailboxHolder> mailbox_holder, 94 const ReleaseMailboxCB& mailbox_holder_release_cb, 95 const gfx::Size& coded_size, 96 const gfx::Rect& visible_rect, 97 const gfx::Size& natural_size, 98 base::TimeDelta timestamp, 99 const ReadPixelsCB& read_pixels_cb) { 100 scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE, 101 coded_size, 102 visible_rect, 103 natural_size, 104 timestamp, 105 false)); 106 frame->mailbox_holder_ = mailbox_holder.Pass(); 107 frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb; 108 frame->read_pixels_cb_ = read_pixels_cb; 109 110 return frame; 111} 112 113void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) { 114 DCHECK_EQ(format_, NATIVE_TEXTURE); 115 if (!read_pixels_cb_.is_null()) 116 read_pixels_cb_.Run(pixels); 117} 118 119// static 120scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory( 121 Format format, 122 const gfx::Size& coded_size, 123 const gfx::Rect& visible_rect, 124 const gfx::Size& natural_size, 125 uint8* data, 126 size_t data_size, 127 base::SharedMemoryHandle handle, 128 base::TimeDelta timestamp, 129 const base::Closure& no_longer_needed_cb) { 130 if (data_size < AllocationSize(format, coded_size)) 131 return NULL; 132 133 switch (format) { 134 case I420: { 135 scoped_refptr<VideoFrame> frame(new VideoFrame( 136 format, coded_size, visible_rect, natural_size, timestamp, false)); 137 frame->shared_memory_handle_ = handle; 138 frame->strides_[kYPlane] = coded_size.width(); 139 frame->strides_[kUPlane] = coded_size.width() / 2; 140 frame->strides_[kVPlane] = coded_size.width() / 2; 141 frame->data_[kYPlane] = data; 142 frame->data_[kUPlane] = data + coded_size.GetArea(); 143 frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4); 144 frame->no_longer_needed_cb_ = no_longer_needed_cb; 145 return frame; 146 } 147 default: 148 NOTIMPLEMENTED(); 149 return NULL; 150 } 151} 152 153// static 154scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData( 155 Format format, 156 const gfx::Size& coded_size, 157 const gfx::Rect& visible_rect, 158 const gfx::Size& natural_size, 159 int32 y_stride, 160 int32 u_stride, 161 int32 v_stride, 162 uint8* y_data, 163 uint8* u_data, 164 uint8* v_data, 165 base::TimeDelta timestamp, 166 const base::Closure& no_longer_needed_cb) { 167 DCHECK(format == YV12 || format == YV16 || format == I420) << format; 168 scoped_refptr<VideoFrame> frame(new VideoFrame( 169 format, coded_size, visible_rect, natural_size, timestamp, false)); 170 frame->strides_[kYPlane] = y_stride; 171 frame->strides_[kUPlane] = u_stride; 172 frame->strides_[kVPlane] = v_stride; 173 frame->data_[kYPlane] = y_data; 174 frame->data_[kUPlane] = u_data; 175 frame->data_[kVPlane] = v_data; 176 frame->no_longer_needed_cb_ = no_longer_needed_cb; 177 return frame; 178} 179 180// static 181scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame( 182 const scoped_refptr<VideoFrame>& frame, 183 const gfx::Rect& visible_rect, 184 const gfx::Size& natural_size, 185 const base::Closure& no_longer_needed_cb) { 186 DCHECK(frame->visible_rect().Contains(visible_rect)); 187 scoped_refptr<VideoFrame> wrapped_frame(new VideoFrame( 188 frame->format(), frame->coded_size(), visible_rect, natural_size, 189 frame->GetTimestamp(), frame->end_of_stream())); 190 191 for (size_t i = 0; i < NumPlanes(frame->format()); ++i) { 192 wrapped_frame->strides_[i] = frame->stride(i); 193 wrapped_frame->data_[i] = frame->data(i); 194 } 195 196 wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb; 197 return wrapped_frame; 198} 199 200// static 201scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() { 202 return new VideoFrame(VideoFrame::UNKNOWN, 203 gfx::Size(), 204 gfx::Rect(), 205 gfx::Size(), 206 kNoTimestamp(), 207 true); 208} 209 210// static 211scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame( 212 const gfx::Size& size, 213 uint8 y, uint8 u, uint8 v, 214 base::TimeDelta timestamp) { 215 DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size)); 216 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( 217 VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); 218 FillYUV(frame.get(), y, u, v); 219 return frame; 220} 221 222// static 223scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) { 224 const uint8 kBlackY = 0x00; 225 const uint8 kBlackUV = 0x80; 226 const base::TimeDelta kZero; 227 return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero); 228} 229 230#if defined(VIDEO_HOLE) 231// This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not 232// maintained by the general compositor team. Please contact the following 233// people instead: 234// 235// wonsik@chromium.org 236// ycheo@chromium.org 237 238// static 239scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame( 240 const gfx::Size& size) { 241 DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size)); 242 scoped_refptr<VideoFrame> frame(new VideoFrame( 243 VideoFrame::HOLE, size, gfx::Rect(size), size, base::TimeDelta(), false)); 244 return frame; 245} 246#endif // defined(VIDEO_HOLE) 247 248// static 249size_t VideoFrame::NumPlanes(Format format) { 250 switch (format) { 251 case VideoFrame::NATIVE_TEXTURE: 252#if defined(VIDEO_HOLE) 253 case VideoFrame::HOLE: 254#endif // defined(VIDEO_HOLE) 255 return 0; 256 case VideoFrame::YV12: 257 case VideoFrame::YV16: 258 case VideoFrame::I420: 259 case VideoFrame::YV12J: 260 return 3; 261 case VideoFrame::YV12A: 262 return 4; 263 case VideoFrame::UNKNOWN: 264 break; 265 } 266 NOTREACHED() << "Unsupported video frame format: " << format; 267 return 0; 268} 269 270static inline size_t RoundUp(size_t value, size_t alignment) { 271 // Check that |alignment| is a power of 2. 272 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); 273 return ((value + (alignment - 1)) & ~(alignment-1)); 274} 275 276// static 277size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) { 278 size_t total = 0; 279 for (size_t i = 0; i < NumPlanes(format); ++i) 280 total += PlaneAllocationSize(format, i, coded_size); 281 return total; 282} 283 284// static 285size_t VideoFrame::PlaneAllocationSize(Format format, 286 size_t plane, 287 const gfx::Size& coded_size) { 288 const size_t area = 289 RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2); 290 switch (format) { 291 case VideoFrame::YV12: 292 case VideoFrame::YV12J: 293 case VideoFrame::I420: { 294 switch (plane) { 295 case VideoFrame::kYPlane: 296 return area; 297 case VideoFrame::kUPlane: 298 case VideoFrame::kVPlane: 299 return area / 4; 300 default: 301 break; 302 } 303 } 304 case VideoFrame::YV12A: { 305 switch (plane) { 306 case VideoFrame::kYPlane: 307 case VideoFrame::kAPlane: 308 return area; 309 case VideoFrame::kUPlane: 310 case VideoFrame::kVPlane: 311 return area / 4; 312 default: 313 break; 314 } 315 } 316 case VideoFrame::YV16: { 317 switch (plane) { 318 case VideoFrame::kYPlane: 319 return area; 320 case VideoFrame::kUPlane: 321 case VideoFrame::kVPlane: 322 return area / 2; 323 default: 324 break; 325 } 326 } 327 case VideoFrame::UNKNOWN: 328 case VideoFrame::NATIVE_TEXTURE: 329#if defined(VIDEO_HOLE) 330 case VideoFrame::HOLE: 331#endif // defined(VIDEO_HOLE) 332 break; 333 } 334 NOTREACHED() << "Unsupported video frame format/plane: " 335 << format << "/" << plane; 336 return 0; 337} 338 339// Release data allocated by AllocateYUV(). 340static void ReleaseData(uint8* data) { 341 DCHECK(data); 342 base::AlignedFree(data); 343} 344 345void VideoFrame::AllocateYUV() { 346 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || 347 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 || 348 format_ == VideoFrame::YV12J); 349 // Align Y rows at least at 16 byte boundaries. The stride for both 350 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for 351 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in 352 // the case of YV12 the strides are identical for the same width surface, but 353 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as 354 // YV16. We also round the height of the surface allocated to be an even 355 // number to avoid any potential of faulting by code that attempts to access 356 // the Y values of the final row, but assumes that the last row of U & V 357 // applies to a full two rows of Y. YV12A is the same as YV12, but with an 358 // additional alpha plane that has the same size and alignment as the Y plane. 359 360 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 361 kFrameSizeAlignment); 362 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 363 kFrameSizeAlignment); 364 // The *2 here is because some formats (e.g. h264) allow interlaced coding, 365 // and then the size needs to be a multiple of two macroblocks (vertically). 366 // See libavcodec/utils.c:avcodec_align_dimensions2(). 367 size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); 368 size_t uv_height = 369 (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A || 370 format_ == VideoFrame::I420) 371 ? y_height / 2 372 : y_height; 373 size_t y_bytes = y_height * y_stride; 374 size_t uv_bytes = uv_height * uv_stride; 375 size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0; 376 377 // The extra line of UV being allocated is because h264 chroma MC 378 // overreads by one line in some cases, see libavcodec/utils.c: 379 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: 380 // put_h264_chroma_mc4_ssse3(). 381 uint8* data = reinterpret_cast<uint8*>( 382 base::AlignedAlloc( 383 y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding, 384 kFrameAddressAlignment)); 385 no_longer_needed_cb_ = base::Bind(&ReleaseData, data); 386 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); 387 data_[VideoFrame::kYPlane] = data; 388 data_[VideoFrame::kUPlane] = data + y_bytes; 389 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; 390 strides_[VideoFrame::kYPlane] = y_stride; 391 strides_[VideoFrame::kUPlane] = uv_stride; 392 strides_[VideoFrame::kVPlane] = uv_stride; 393 if (format_ == YV12A) { 394 data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes); 395 strides_[VideoFrame::kAPlane] = y_stride; 396 } 397} 398 399VideoFrame::VideoFrame(VideoFrame::Format format, 400 const gfx::Size& coded_size, 401 const gfx::Rect& visible_rect, 402 const gfx::Size& natural_size, 403 base::TimeDelta timestamp, 404 bool end_of_stream) 405 : format_(format), 406 coded_size_(coded_size), 407 visible_rect_(visible_rect), 408 natural_size_(natural_size), 409 shared_memory_handle_(base::SharedMemory::NULLHandle()), 410 timestamp_(timestamp), 411 end_of_stream_(end_of_stream) { 412 memset(&strides_, 0, sizeof(strides_)); 413 memset(&data_, 0, sizeof(data_)); 414} 415 416VideoFrame::~VideoFrame() { 417 if (!mailbox_holder_release_cb_.is_null()) { 418 base::ResetAndReturn(&mailbox_holder_release_cb_) 419 .Run(mailbox_holder_.Pass()); 420 } 421 if (!no_longer_needed_cb_.is_null()) 422 base::ResetAndReturn(&no_longer_needed_cb_).Run(); 423} 424 425bool VideoFrame::IsValidPlane(size_t plane) const { 426 return (plane < NumPlanes(format_)); 427} 428 429int VideoFrame::stride(size_t plane) const { 430 DCHECK(IsValidPlane(plane)); 431 return strides_[plane]; 432} 433 434int VideoFrame::row_bytes(size_t plane) const { 435 DCHECK(IsValidPlane(plane)); 436 int width = coded_size_.width(); 437 switch (format_) { 438 // Planar, 8bpp. 439 case YV12A: 440 if (plane == kAPlane) 441 return width; 442 // Fallthrough. 443 case YV12: 444 case YV16: 445 case I420: 446 case YV12J: 447 if (plane == kYPlane) 448 return width; 449 return RoundUp(width, 2) / 2; 450 451 default: 452 break; 453 } 454 455 // Intentionally leave out non-production formats. 456 NOTREACHED() << "Unsupported video frame format: " << format_; 457 return 0; 458} 459 460int VideoFrame::rows(size_t plane) const { 461 DCHECK(IsValidPlane(plane)); 462 int height = coded_size_.height(); 463 switch (format_) { 464 case YV16: 465 return height; 466 467 case YV12A: 468 if (plane == kAPlane) 469 return height; 470 // Fallthrough. 471 case YV12: 472 case I420: 473 if (plane == kYPlane) 474 return height; 475 return RoundUp(height, 2) / 2; 476 477 default: 478 break; 479 } 480 481 // Intentionally leave out non-production formats. 482 NOTREACHED() << "Unsupported video frame format: " << format_; 483 return 0; 484} 485 486uint8* VideoFrame::data(size_t plane) const { 487 DCHECK(IsValidPlane(plane)); 488 return data_[plane]; 489} 490 491gpu::MailboxHolder* VideoFrame::mailbox_holder() const { 492 DCHECK_EQ(format_, NATIVE_TEXTURE); 493 return mailbox_holder_.get(); 494} 495 496base::SharedMemoryHandle VideoFrame::shared_memory_handle() const { 497 return shared_memory_handle_; 498} 499 500void VideoFrame::HashFrameForTesting(base::MD5Context* context) { 501 for (int plane = 0; plane < kMaxPlanes; ++plane) { 502 if (!IsValidPlane(plane)) 503 break; 504 for (int row = 0; row < rows(plane); ++row) { 505 base::MD5Update(context, base::StringPiece( 506 reinterpret_cast<char*>(data(plane) + stride(plane) * row), 507 row_bytes(plane))); 508 } 509 } 510} 511 512} // namespace media 513