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