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