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