video_frame.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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)); 30 switch (format) { 31 case VideoFrame::RGB32: 32 frame->AllocateRGB(4u); 33 break; 34 case VideoFrame::YV12: 35 case VideoFrame::YV12A: 36 case VideoFrame::YV16: 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::INVALID: 49 return "INVALID"; 50 case VideoFrame::RGB32: 51 return "RGB32"; 52 case VideoFrame::YV12: 53 return "YV12"; 54 case VideoFrame::YV16: 55 return "YV16"; 56 case VideoFrame::EMPTY: 57 return "EMPTY"; 58 case VideoFrame::I420: 59 return "I420"; 60 case VideoFrame::NATIVE_TEXTURE: 61 return "NATIVE_TEXTURE"; 62#if defined(GOOGLE_TV) 63 case VideoFrame::HOLE: 64 return "HOLE"; 65#endif 66 case VideoFrame::YV12A: 67 return "YV12A"; 68 } 69 NOTREACHED() << "Invalid videoframe format provided: " << format; 70 return ""; 71} 72 73// static 74bool VideoFrame::IsValidConfig(VideoFrame::Format format, 75 const gfx::Size& coded_size, 76 const gfx::Rect& visible_rect, 77 const gfx::Size& natural_size) { 78 return (format != VideoFrame::INVALID && 79 !coded_size.IsEmpty() && 80 coded_size.GetArea() <= limits::kMaxCanvas && 81 coded_size.width() <= limits::kMaxDimension && 82 coded_size.height() <= limits::kMaxDimension && 83 !visible_rect.IsEmpty() && 84 visible_rect.x() >= 0 && visible_rect.y() >= 0 && 85 visible_rect.right() <= coded_size.width() && 86 visible_rect.bottom() <= coded_size.height() && 87 !natural_size.IsEmpty() && 88 natural_size.GetArea() <= limits::kMaxCanvas && 89 natural_size.width() <= limits::kMaxDimension && 90 natural_size.height() <= limits::kMaxDimension); 91} 92 93// static 94scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( 95 const scoped_refptr<MailboxHolder>& mailbox_holder, 96 uint32 texture_target, 97 const gfx::Size& coded_size, 98 const gfx::Rect& visible_rect, 99 const gfx::Size& natural_size, 100 base::TimeDelta timestamp, 101 const ReadPixelsCB& read_pixels_cb, 102 const base::Closure& no_longer_needed_cb) { 103 scoped_refptr<VideoFrame> frame(new VideoFrame( 104 NATIVE_TEXTURE, coded_size, visible_rect, natural_size, timestamp)); 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::WrapExternalYuvData( 121 Format format, 122 const gfx::Size& coded_size, 123 const gfx::Rect& visible_rect, 124 const gfx::Size& natural_size, 125 int32 y_stride, int32 u_stride, int32 v_stride, 126 uint8* y_data, uint8* u_data, uint8* v_data, 127 base::TimeDelta timestamp, 128 base::SharedMemoryHandle shm_handle, 129 const base::Closure& no_longer_needed_cb) { 130 DCHECK(format == YV12 || format == YV16 || format == I420) << format; 131 scoped_refptr<VideoFrame> frame(new VideoFrame( 132 format, coded_size, visible_rect, natural_size, timestamp)); 133 frame->shared_memory_handle_ = shm_handle; 134 frame->strides_[kYPlane] = y_stride; 135 frame->strides_[kUPlane] = u_stride; 136 frame->strides_[kVPlane] = v_stride; 137 frame->data_[kYPlane] = y_data; 138 frame->data_[kUPlane] = u_data; 139 frame->data_[kVPlane] = v_data; 140 frame->no_longer_needed_cb_ = no_longer_needed_cb; 141 return frame; 142} 143 144// static 145scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() { 146 return new VideoFrame( 147 VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(), 148 base::TimeDelta()); 149} 150 151// static 152scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame( 153 const gfx::Size& size, 154 uint8 y, uint8 u, uint8 v, 155 base::TimeDelta timestamp) { 156 DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size)); 157 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( 158 VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); 159 FillYUV(frame.get(), y, u, v); 160 return frame; 161} 162 163// static 164scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) { 165 const uint8 kBlackY = 0x00; 166 const uint8 kBlackUV = 0x80; 167 const base::TimeDelta kZero; 168 return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero); 169} 170 171#if defined(GOOGLE_TV) 172// This block and other blocks wrapped around #if defined(GOOGLE_TV) is not 173// maintained by the general compositor team. Please contact the following 174// people instead: 175// 176// wonsik@chromium.org 177// ycheo@chromium.org 178 179// static 180scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame( 181 const gfx::Size& size) { 182 DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size)); 183 scoped_refptr<VideoFrame> frame(new VideoFrame( 184 VideoFrame::HOLE, size, gfx::Rect(size), size, base::TimeDelta())); 185 return frame; 186} 187#endif 188 189// static 190size_t VideoFrame::NumPlanes(Format format) { 191 switch (format) { 192 case VideoFrame::NATIVE_TEXTURE: 193#if defined(GOOGLE_TV) 194 case VideoFrame::HOLE: 195#endif 196 return 0; 197 case VideoFrame::RGB32: 198 return 1; 199 case VideoFrame::YV12: 200 case VideoFrame::YV16: 201 return 3; 202 case VideoFrame::YV12A: 203 return 4; 204 case VideoFrame::EMPTY: 205 case VideoFrame::I420: 206 case VideoFrame::INVALID: 207 break; 208 } 209 NOTREACHED() << "Unsupported video frame format: " << format; 210 return 0; 211} 212 213static inline size_t RoundUp(size_t value, size_t alignment) { 214 // Check that |alignment| is a power of 2. 215 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); 216 return ((value + (alignment - 1)) & ~(alignment-1)); 217} 218 219// Release data allocated by AllocateRGB() or AllocateYUV(). 220static void ReleaseData(uint8* data) { 221 DCHECK(data); 222 base::AlignedFree(data); 223} 224 225void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { 226 // Round up to align at least at a 16-byte boundary for each row. 227 // This is sufficient for MMX and SSE2 reads (movq/movdqa). 228 size_t bytes_per_row = RoundUp(coded_size_.width(), 229 kFrameSizeAlignment) * bytes_per_pixel; 230 size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment); 231 strides_[VideoFrame::kRGBPlane] = bytes_per_row; 232 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>( 233 base::AlignedAlloc(bytes_per_row * aligned_height + kFrameSizePadding, 234 kFrameAddressAlignment)); 235 no_longer_needed_cb_ = base::Bind(&ReleaseData, data_[VideoFrame::kRGBPlane]); 236 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); 237 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); 238} 239 240void VideoFrame::AllocateYUV() { 241 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || 242 format_ == VideoFrame::YV12A); 243 // Align Y rows at least at 16 byte boundaries. The stride for both 244 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for 245 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in 246 // the case of YV12 the strides are identical for the same width surface, but 247 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as 248 // YV16. We also round the height of the surface allocated to be an even 249 // number to avoid any potential of faulting by code that attempts to access 250 // the Y values of the final row, but assumes that the last row of U & V 251 // applies to a full two rows of Y. YV12A is the same as YV12, but with an 252 // additional alpha plane that has the same size and alignment as the Y plane. 253 254 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 255 kFrameSizeAlignment); 256 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 257 kFrameSizeAlignment); 258 // The *2 here is because some formats (e.g. h264) allow interlaced coding, 259 // and then the size needs to be a multiple of two macroblocks (vertically). 260 // See libavcodec/utils.c:avcodec_align_dimensions2(). 261 size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); 262 size_t uv_height = (format_ == VideoFrame::YV12 || 263 format_ == VideoFrame::YV12A) ? 264 y_height / 2 : y_height; 265 size_t y_bytes = y_height * y_stride; 266 size_t uv_bytes = uv_height * uv_stride; 267 size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0; 268 269 // The extra line of UV being allocated is because h264 chroma MC 270 // overreads by one line in some cases, see libavcodec/utils.c: 271 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: 272 // put_h264_chroma_mc4_ssse3(). 273 uint8* data = reinterpret_cast<uint8*>( 274 base::AlignedAlloc( 275 y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding, 276 kFrameAddressAlignment)); 277 no_longer_needed_cb_ = base::Bind(&ReleaseData, data); 278 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); 279 data_[VideoFrame::kYPlane] = data; 280 data_[VideoFrame::kUPlane] = data + y_bytes; 281 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; 282 strides_[VideoFrame::kYPlane] = y_stride; 283 strides_[VideoFrame::kUPlane] = uv_stride; 284 strides_[VideoFrame::kVPlane] = uv_stride; 285 if (format_ == YV12A) { 286 data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes); 287 strides_[VideoFrame::kAPlane] = y_stride; 288 } 289} 290 291VideoFrame::VideoFrame(VideoFrame::Format format, 292 const gfx::Size& coded_size, 293 const gfx::Rect& visible_rect, 294 const gfx::Size& natural_size, 295 base::TimeDelta timestamp) 296 : format_(format), 297 coded_size_(coded_size), 298 visible_rect_(visible_rect), 299 natural_size_(natural_size), 300 texture_target_(0), 301 shared_memory_handle_(base::SharedMemory::NULLHandle()), 302 timestamp_(timestamp) { 303 memset(&strides_, 0, sizeof(strides_)); 304 memset(&data_, 0, sizeof(data_)); 305} 306 307VideoFrame::~VideoFrame() { 308 if (!no_longer_needed_cb_.is_null()) 309 base::ResetAndReturn(&no_longer_needed_cb_).Run(); 310} 311 312bool VideoFrame::IsValidPlane(size_t plane) const { 313 return (plane < NumPlanes(format_)); 314} 315 316int VideoFrame::stride(size_t plane) const { 317 DCHECK(IsValidPlane(plane)); 318 return strides_[plane]; 319} 320 321int VideoFrame::row_bytes(size_t plane) const { 322 DCHECK(IsValidPlane(plane)); 323 int width = coded_size_.width(); 324 switch (format_) { 325 // 32bpp. 326 case RGB32: 327 return width * 4; 328 329 // Planar, 8bpp. 330 case YV12: 331 case YV16: 332 case YV12A: 333 if (plane == kYPlane || plane == kAPlane) 334 return width; 335 return RoundUp(width, 2) / 2; 336 337 default: 338 break; 339 } 340 341 // Intentionally leave out non-production formats. 342 NOTREACHED() << "Unsupported video frame format: " << format_; 343 return 0; 344} 345 346int VideoFrame::rows(size_t plane) const { 347 DCHECK(IsValidPlane(plane)); 348 int height = coded_size_.height(); 349 switch (format_) { 350 case RGB32: 351 case YV16: 352 return height; 353 354 case YV12: 355 case YV12A: 356 if (plane == kYPlane || plane == kAPlane) 357 return height; 358 return RoundUp(height, 2) / 2; 359 360 default: 361 break; 362 } 363 364 // Intentionally leave out non-production formats. 365 NOTREACHED() << "Unsupported video frame format: " << format_; 366 return 0; 367} 368 369uint8* VideoFrame::data(size_t plane) const { 370 DCHECK(IsValidPlane(plane)); 371 return data_[plane]; 372} 373 374const scoped_refptr<VideoFrame::MailboxHolder>& VideoFrame::texture_mailbox() 375 const { 376 DCHECK_EQ(format_, NATIVE_TEXTURE); 377 return texture_mailbox_holder_; 378} 379 380uint32 VideoFrame::texture_target() const { 381 DCHECK_EQ(format_, NATIVE_TEXTURE); 382 return texture_target_; 383} 384 385base::SharedMemoryHandle VideoFrame::shared_memory_handle() const { 386 return shared_memory_handle_; 387} 388 389bool VideoFrame::IsEndOfStream() const { 390 return format_ == VideoFrame::EMPTY; 391} 392 393void VideoFrame::HashFrameForTesting(base::MD5Context* context) { 394 for (int plane = 0; plane < kMaxPlanes; ++plane) { 395 if (!IsValidPlane(plane)) 396 break; 397 for (int row = 0; row < rows(plane); ++row) { 398 base::MD5Update(context, base::StringPiece( 399 reinterpret_cast<char*>(data(plane) + stride(plane) * row), 400 row_bytes(plane))); 401 } 402 } 403} 404 405VideoFrame::MailboxHolder::MailboxHolder( 406 const gpu::Mailbox& mailbox, 407 unsigned sync_point, 408 const TextureNoLongerNeededCallback& release_callback) 409 : mailbox_(mailbox), 410 sync_point_(sync_point), 411 release_callback_(release_callback) {} 412 413VideoFrame::MailboxHolder::~MailboxHolder() { 414 if (!release_callback_.is_null()) 415 release_callback_.Run(sync_point_); 416} 417 418} // namespace media 419