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