Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/video_frame.h" | 5 #include "media/base/video_frame.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/aligned_memory.h" | 12 #include "base/memory/aligned_memory.h" |
| 13 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 14 #include "gpu/command_buffer/common/mailbox_holder.h" | 14 #include "gpu/command_buffer/common/mailbox_holder.h" |
| 15 #include "media/base/limits.h" | 15 #include "media/base/limits.h" |
| 16 #include "media/base/video_util.h" | 16 #include "media/base/video_util.h" |
| 17 #include "ui/gfx/point.h" | |
| 17 | 18 |
| 18 #if !defined(MEDIA_FOR_CAST_IOS) | 19 #if !defined(MEDIA_FOR_CAST_IOS) |
| 19 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
| 20 #endif | 21 #endif |
| 21 | 22 |
| 22 namespace media { | 23 namespace media { |
| 23 | 24 |
| 25 static bool IsPowerOfTwo(size_t x) { | |
| 26 return x != 0 && (x & (x - 1)) == 0; | |
| 27 } | |
| 28 | |
| 24 static inline size_t RoundUp(size_t value, size_t alignment) { | 29 static inline size_t RoundUp(size_t value, size_t alignment) { |
| 25 // Check that |alignment| is a power of 2. | 30 DCHECK(IsPowerOfTwo(alignment)); |
| 26 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | |
| 27 return ((value + (alignment - 1)) & ~(alignment - 1)); | 31 return ((value + (alignment - 1)) & ~(alignment - 1)); |
| 28 } | 32 } |
| 29 | 33 |
| 34 static inline size_t RoundDown(size_t value, size_t alignment) { | |
| 35 DCHECK(IsPowerOfTwo(alignment)); | |
| 36 return value & ~(alignment - 1); | |
| 37 } | |
| 38 | |
| 39 // Returns the pixel size per element for given |plane| and |format|. E.g. 2x2 | |
| 40 // for the U-plane in I420. | |
| 41 static gfx::Size SampleSize(VideoFrame::Format format, size_t plane) { | |
| 42 DCHECK(VideoFrame::IsValidPlane(plane, format)); | |
| 43 | |
| 44 switch (plane) { | |
| 45 case VideoFrame::kYPlane: | |
| 46 case VideoFrame::kAPlane: | |
| 47 return gfx::Size(1, 1); | |
| 48 | |
| 49 case VideoFrame::kUPlane: // and VideoFrame::kUVPlane: | |
| 50 case VideoFrame::kVPlane: | |
| 51 switch (format) { | |
| 52 case VideoFrame::YV24: | |
| 53 return gfx::Size(1, 1); | |
| 54 | |
| 55 case VideoFrame::YV16: | |
| 56 return gfx::Size(2, 1); | |
| 57 | |
| 58 case VideoFrame::YV12: | |
| 59 case VideoFrame::YV12J: | |
| 60 case VideoFrame::I420: | |
| 61 case VideoFrame::YV12A: | |
| 62 case VideoFrame::NV12: | |
| 63 return gfx::Size(2, 2); | |
| 64 | |
| 65 case VideoFrame::UNKNOWN: | |
| 66 #if defined(VIDEO_HOLE) | |
| 67 case VideoFrame::HOLE: | |
| 68 #endif // defined(VIDEO_HOLE) | |
| 69 case VideoFrame::NATIVE_TEXTURE: | |
| 70 break; | |
| 71 } | |
| 72 } | |
| 73 NOTREACHED(); | |
| 74 return gfx::Size(); | |
| 75 } | |
| 76 | |
| 77 // Return the alignment for the whole frame, calculated as the max of the | |
| 78 // alignment for each individual plane. | |
| 79 static gfx::Size CommonAlignment(VideoFrame::Format format) { | |
| 80 int max_sample_width = 0; | |
| 81 int max_sample_height = 0; | |
| 82 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) { | |
| 83 const gfx::Size sample_size = SampleSize(format, plane); | |
| 84 max_sample_width = std::max(max_sample_width, sample_size.width()); | |
| 85 max_sample_height = std::max(max_sample_height, sample_size.height()); | |
| 86 } | |
| 87 return gfx::Size(max_sample_width, max_sample_height); | |
| 88 } | |
| 89 | |
| 90 // Returns the number of bytes per element for given |plane| and |format|. E.g. | |
| 91 // 2 for the UV plane in NV12. | |
| 92 static int BytesPerElement(VideoFrame::Format format, size_t plane) { | |
| 93 DCHECK(VideoFrame::IsValidPlane(plane, format)); | |
| 94 return (format == VideoFrame::NV12 && plane == VideoFrame::kUVPlane) ? 2 : 1; | |
| 95 } | |
| 96 | |
| 30 // Rounds up |coded_size| if necessary for |format|. | 97 // Rounds up |coded_size| if necessary for |format|. |
| 31 static gfx::Size AdjustCodedSize(VideoFrame::Format format, | 98 static gfx::Size AdjustCodedSize(VideoFrame::Format format, |
| 32 const gfx::Size& coded_size) { | 99 const gfx::Size& coded_size) { |
| 33 gfx::Size new_coded_size(coded_size); | 100 const gfx::Size alignment = CommonAlignment(format); |
| 34 switch (format) { | 101 return gfx::Size(RoundUp(coded_size.width(), alignment.width()), |
| 35 case VideoFrame::YV12: | 102 RoundUp(coded_size.height(), alignment.height())); |
| 36 case VideoFrame::YV12A: | |
| 37 case VideoFrame::I420: | |
| 38 case VideoFrame::YV12J: | |
| 39 new_coded_size.set_height(RoundUp(new_coded_size.height(), 2)); | |
| 40 // Fallthrough. | |
| 41 case VideoFrame::YV16: | |
| 42 new_coded_size.set_width(RoundUp(new_coded_size.width(), 2)); | |
| 43 break; | |
| 44 default: | |
| 45 break; | |
| 46 } | |
| 47 return new_coded_size; | |
| 48 } | 103 } |
| 49 | 104 |
| 50 // static | 105 // static |
| 51 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 106 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
| 52 VideoFrame::Format format, | 107 VideoFrame::Format format, |
| 53 const gfx::Size& coded_size, | 108 const gfx::Size& coded_size, |
| 54 const gfx::Rect& visible_rect, | 109 const gfx::Rect& visible_rect, |
| 55 const gfx::Size& natural_size, | 110 const gfx::Size& natural_size, |
| 56 base::TimeDelta timestamp) { | 111 base::TimeDelta timestamp) { |
| 57 DCHECK(format != VideoFrame::UNKNOWN && | 112 DCHECK(format != VideoFrame::UNKNOWN && |
| 58 format != VideoFrame::NV12 && | 113 format != VideoFrame::NV12 && |
| 59 format != VideoFrame::NATIVE_TEXTURE); | 114 format != VideoFrame::NATIVE_TEXTURE); |
| 60 #if defined(VIDEO_HOLE) | 115 #if defined(VIDEO_HOLE) |
| 61 DCHECK(format != VideoFrame::HOLE); | 116 DCHECK(format != VideoFrame::HOLE); |
| 62 #endif // defined(VIDEO_HOLE) | 117 #endif // defined(VIDEO_HOLE) |
| 63 | 118 |
| 64 // Since we're creating a new YUV frame (and allocating memory for it | 119 // Since we're creating a new YUV frame (and allocating memory for it |
| 65 // ourselves), we can pad the requested |coded_size| if necessary if the | 120 // ourselves), we can pad the requested |coded_size| if necessary if the |
| 66 // request does not line up on sample boundaries. | 121 // request does not line up on sample boundaries. |
| 67 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); | 122 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); |
|
scherkus (not reviewing)
2014/10/22 23:01:49
general tip for the future: try to avoid making th
magjed_chromium
2014/10/23 11:44:30
Yeah, sorry about that. I will keep that in mind i
| |
| 68 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); | 123 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); |
| 69 | 124 |
| 70 scoped_refptr<VideoFrame> frame( | 125 scoped_refptr<VideoFrame> frame( |
| 71 new VideoFrame(format, | 126 new VideoFrame(format, |
| 72 new_coded_size, | 127 new_coded_size, |
| 73 visible_rect, | 128 visible_rect, |
| 74 natural_size, | 129 natural_size, |
| 75 scoped_ptr<gpu::MailboxHolder>(), | 130 scoped_ptr<gpu::MailboxHolder>(), |
| 76 timestamp, | 131 timestamp, |
| 77 false)); | 132 false)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 natural_size.GetArea() > limits::kMaxCanvas || | 179 natural_size.GetArea() > limits::kMaxCanvas || |
| 125 natural_size.width() > limits::kMaxDimension || | 180 natural_size.width() > limits::kMaxDimension || |
| 126 natural_size.height() > limits::kMaxDimension) | 181 natural_size.height() > limits::kMaxDimension) |
| 127 return false; | 182 return false; |
| 128 | 183 |
| 129 // Check format-specific width/height requirements. | 184 // Check format-specific width/height requirements. |
| 130 switch (format) { | 185 switch (format) { |
| 131 case VideoFrame::UNKNOWN: | 186 case VideoFrame::UNKNOWN: |
| 132 return (coded_size.IsEmpty() && visible_rect.IsEmpty() && | 187 return (coded_size.IsEmpty() && visible_rect.IsEmpty() && |
| 133 natural_size.IsEmpty()); | 188 natural_size.IsEmpty()); |
| 189 | |
| 190 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are | |
| 191 // allowed to skip the below check. | |
| 192 case VideoFrame::NATIVE_TEXTURE: | |
| 193 #if defined(VIDEO_HOLE) | |
| 194 case VideoFrame::HOLE: | |
| 195 #endif // defined(VIDEO_HOLE) | |
| 196 return true; | |
| 197 | |
| 134 case VideoFrame::YV24: | 198 case VideoFrame::YV24: |
| 135 break; | |
| 136 case VideoFrame::YV12: | 199 case VideoFrame::YV12: |
| 137 case VideoFrame::YV12J: | 200 case VideoFrame::YV12J: |
| 138 case VideoFrame::I420: | 201 case VideoFrame::I420: |
| 139 case VideoFrame::YV12A: | 202 case VideoFrame::YV12A: |
| 140 case VideoFrame::NV12: | 203 case VideoFrame::NV12: |
| 141 // Subsampled YUV formats have width/height requirements. | |
| 142 if (static_cast<size_t>(coded_size.height()) < | |
| 143 RoundUp(visible_rect.bottom(), 2)) | |
| 144 return false; | |
| 145 // Fallthrough. | |
| 146 case VideoFrame::YV16: | 204 case VideoFrame::YV16: |
| 147 if (static_cast<size_t>(coded_size.width()) < | 205 // Check that software-allocated buffer formats are aligned correctly and |
| 148 RoundUp(visible_rect.right(), 2)) | 206 // not empty. |
| 149 return false; | 207 const gfx::Size alignment = CommonAlignment(format); |
| 150 break; | 208 return RoundUp(visible_rect.right(), alignment.width()) <= |
| 151 case VideoFrame::NATIVE_TEXTURE: | 209 static_cast<size_t>(coded_size.width()) && |
| 152 #if defined(VIDEO_HOLE) | 210 RoundUp(visible_rect.bottom(), alignment.height()) <= |
| 153 case VideoFrame::HOLE: | 211 static_cast<size_t>(coded_size.height()) && |
| 154 #endif // defined(VIDEO_HOLE) | 212 !coded_size.IsEmpty() && !visible_rect.IsEmpty() && |
| 155 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are | 213 !natural_size.IsEmpty(); |
| 156 // allowed to skip the below check and be empty. | |
| 157 return true; | |
| 158 } | 214 } |
| 159 | 215 |
| 160 // Check that software-allocated buffer formats are not empty. | 216 NOTREACHED(); |
| 161 return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() && | 217 return false; |
| 162 !natural_size.IsEmpty()); | |
| 163 } | 218 } |
| 164 | 219 |
| 165 // static | 220 // static |
| 166 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( | 221 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( |
| 167 scoped_ptr<gpu::MailboxHolder> mailbox_holder, | 222 scoped_ptr<gpu::MailboxHolder> mailbox_holder, |
| 168 const ReleaseMailboxCB& mailbox_holder_release_cb, | 223 const ReleaseMailboxCB& mailbox_holder_release_cb, |
| 169 const gfx::Size& coded_size, | 224 const gfx::Size& coded_size, |
| 170 const gfx::Rect& visible_rect, | 225 const gfx::Rect& visible_rect, |
| 171 const gfx::Size& natural_size, | 226 const gfx::Size& natural_size, |
| 172 base::TimeDelta timestamp, | 227 base::TimeDelta timestamp, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 196 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory( | 251 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory( |
| 197 Format format, | 252 Format format, |
| 198 const gfx::Size& coded_size, | 253 const gfx::Size& coded_size, |
| 199 const gfx::Rect& visible_rect, | 254 const gfx::Rect& visible_rect, |
| 200 const gfx::Size& natural_size, | 255 const gfx::Size& natural_size, |
| 201 uint8* data, | 256 uint8* data, |
| 202 size_t data_size, | 257 size_t data_size, |
| 203 base::SharedMemoryHandle handle, | 258 base::SharedMemoryHandle handle, |
| 204 base::TimeDelta timestamp, | 259 base::TimeDelta timestamp, |
| 205 const base::Closure& no_longer_needed_cb) { | 260 const base::Closure& no_longer_needed_cb) { |
| 206 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); | 261 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); |
| 207 | 262 |
| 208 if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size)) | 263 if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size)) |
| 209 return NULL; | 264 return NULL; |
| 210 if (data_size < AllocationSize(format, new_coded_size)) | 265 if (data_size < AllocationSize(format, new_coded_size)) |
| 211 return NULL; | 266 return NULL; |
| 212 | 267 |
| 213 switch (format) { | 268 switch (format) { |
| 214 case VideoFrame::I420: { | 269 case VideoFrame::I420: { |
| 215 scoped_refptr<VideoFrame> frame( | 270 scoped_refptr<VideoFrame> frame( |
| 216 new VideoFrame(format, | 271 new VideoFrame(format, |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 284 #endif | 339 #endif |
| 285 | 340 |
| 286 #if defined(OS_MACOSX) | 341 #if defined(OS_MACOSX) |
| 287 // static | 342 // static |
| 288 scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer( | 343 scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer( |
| 289 CVPixelBufferRef cv_pixel_buffer, | 344 CVPixelBufferRef cv_pixel_buffer, |
| 290 base::TimeDelta timestamp) { | 345 base::TimeDelta timestamp) { |
| 291 DCHECK(cv_pixel_buffer); | 346 DCHECK(cv_pixel_buffer); |
| 292 DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID()); | 347 DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID()); |
| 293 | 348 |
| 294 OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer); | 349 const OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer); |
| 295 Format format; | 350 Format format; |
| 296 // There are very few compatible CV pixel formats, so just check each. | 351 // There are very few compatible CV pixel formats, so just check each. |
| 297 if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) { | 352 if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) { |
| 298 format = Format::I420; | 353 format = Format::I420; |
| 299 } else if (cv_format == kCVPixelFormatType_444YpCbCr8) { | 354 } else if (cv_format == kCVPixelFormatType_444YpCbCr8) { |
| 300 format = Format::YV24; | 355 format = Format::YV24; |
| 301 } else if (cv_format == '420v') { | 356 } else if (cv_format == '420v') { |
| 302 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the | 357 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the |
| 303 // minimum OS X and iOS SDKs permits it. | 358 // minimum OS X and iOS SDKs permits it. |
| 304 format = Format::NV12; | 359 format = Format::NV12; |
| 305 } else { | 360 } else { |
| 306 DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format; | 361 DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format; |
| 307 return NULL; | 362 return NULL; |
| 308 } | 363 } |
| 309 | 364 |
| 310 gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer)); | 365 const gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer)); |
| 311 gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer)); | 366 const gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer)); |
| 312 gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer)); | 367 const gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer)); |
| 313 | 368 |
| 314 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) | 369 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) |
| 315 return NULL; | 370 return NULL; |
| 316 | 371 |
| 317 scoped_refptr<VideoFrame> frame( | 372 scoped_refptr<VideoFrame> frame( |
| 318 new VideoFrame(format, | 373 new VideoFrame(format, |
| 319 coded_size, | 374 coded_size, |
| 320 visible_rect, | 375 visible_rect, |
| 321 natural_size, | 376 natural_size, |
| 322 scoped_ptr<gpu::MailboxHolder>(), | 377 scoped_ptr<gpu::MailboxHolder>(), |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 335 const gfx::Rect& visible_rect, | 390 const gfx::Rect& visible_rect, |
| 336 const gfx::Size& natural_size, | 391 const gfx::Size& natural_size, |
| 337 int32 y_stride, | 392 int32 y_stride, |
| 338 int32 u_stride, | 393 int32 u_stride, |
| 339 int32 v_stride, | 394 int32 v_stride, |
| 340 uint8* y_data, | 395 uint8* y_data, |
| 341 uint8* u_data, | 396 uint8* u_data, |
| 342 uint8* v_data, | 397 uint8* v_data, |
| 343 base::TimeDelta timestamp, | 398 base::TimeDelta timestamp, |
| 344 const base::Closure& no_longer_needed_cb) { | 399 const base::Closure& no_longer_needed_cb) { |
| 345 gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); | 400 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); |
| 346 CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); | 401 CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); |
| 347 | 402 |
| 348 scoped_refptr<VideoFrame> frame( | 403 scoped_refptr<VideoFrame> frame( |
| 349 new VideoFrame(format, | 404 new VideoFrame(format, |
| 350 new_coded_size, | 405 new_coded_size, |
| 351 visible_rect, | 406 visible_rect, |
| 352 natural_size, | 407 natural_size, |
| 353 scoped_ptr<gpu::MailboxHolder>(), | 408 scoped_ptr<gpu::MailboxHolder>(), |
| 354 timestamp, | 409 timestamp, |
| 355 false)); | 410 false)); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 size_t total = 0; | 545 size_t total = 0; |
| 491 for (size_t i = 0; i < NumPlanes(format); ++i) | 546 for (size_t i = 0; i < NumPlanes(format); ++i) |
| 492 total += PlaneAllocationSize(format, i, coded_size); | 547 total += PlaneAllocationSize(format, i, coded_size); |
| 493 return total; | 548 return total; |
| 494 } | 549 } |
| 495 | 550 |
| 496 // static | 551 // static |
| 497 gfx::Size VideoFrame::PlaneSize(Format format, | 552 gfx::Size VideoFrame::PlaneSize(Format format, |
| 498 size_t plane, | 553 size_t plane, |
| 499 const gfx::Size& coded_size) { | 554 const gfx::Size& coded_size) { |
| 555 DCHECK(IsValidPlane(plane, format)); | |
| 556 | |
| 500 // Align to multiple-of-two size overall. This ensures that non-subsampled | 557 // Align to multiple-of-two size overall. This ensures that non-subsampled |
| 501 // planes can be addressed by pixel with the same scaling as the subsampled | 558 // planes can be addressed by pixel with the same scaling as the subsampled |
| 502 // planes. | 559 // planes. |
| 503 const int width = RoundUp(coded_size.width(), 2); | 560 const int width = RoundUp(coded_size.width(), 2); |
| 504 const int height = RoundUp(coded_size.height(), 2); | 561 const int height = RoundUp(coded_size.height(), 2); |
| 505 switch (format) { | 562 |
| 506 case VideoFrame::YV24: | 563 const gfx::Size subsample = SampleSize(format, plane); |
| 507 switch (plane) { | 564 DCHECK(width % subsample.width() == 0 && height % subsample.height() == 0); |
|
scherkus (not reviewing)
2014/10/22 23:01:49
if this fails we won't know which condition failed
magjed_chromium
2014/10/23 11:44:31
Done.
| |
| 508 case VideoFrame::kYPlane: | 565 return gfx::Size(BytesPerElement(format, plane) * width / subsample.width(), |
| 509 case VideoFrame::kUPlane: | 566 height / subsample.height()); |
| 510 case VideoFrame::kVPlane: | |
| 511 return gfx::Size(width, height); | |
| 512 default: | |
| 513 break; | |
| 514 } | |
| 515 break; | |
| 516 case VideoFrame::YV12: | |
| 517 case VideoFrame::YV12J: | |
| 518 case VideoFrame::I420: | |
| 519 switch (plane) { | |
| 520 case VideoFrame::kYPlane: | |
| 521 return gfx::Size(width, height); | |
| 522 case VideoFrame::kUPlane: | |
| 523 case VideoFrame::kVPlane: | |
| 524 return gfx::Size(width / 2, height / 2); | |
| 525 default: | |
| 526 break; | |
| 527 } | |
| 528 break; | |
| 529 case VideoFrame::YV12A: | |
| 530 switch (plane) { | |
| 531 case VideoFrame::kYPlane: | |
| 532 case VideoFrame::kAPlane: | |
| 533 return gfx::Size(width, height); | |
| 534 case VideoFrame::kUPlane: | |
| 535 case VideoFrame::kVPlane: | |
| 536 return gfx::Size(width / 2, height / 2); | |
| 537 default: | |
| 538 break; | |
| 539 } | |
| 540 break; | |
| 541 case VideoFrame::YV16: | |
| 542 switch (plane) { | |
| 543 case VideoFrame::kYPlane: | |
| 544 return gfx::Size(width, height); | |
| 545 case VideoFrame::kUPlane: | |
| 546 case VideoFrame::kVPlane: | |
| 547 return gfx::Size(width / 2, height); | |
| 548 default: | |
| 549 break; | |
| 550 } | |
| 551 break; | |
| 552 case VideoFrame::NV12: | |
| 553 switch (plane) { | |
| 554 case VideoFrame::kYPlane: | |
| 555 return gfx::Size(width, height); | |
| 556 case VideoFrame::kUVPlane: | |
| 557 return gfx::Size(width, height / 2); | |
| 558 default: | |
| 559 break; | |
| 560 } | |
| 561 break; | |
| 562 case VideoFrame::UNKNOWN: | |
| 563 case VideoFrame::NATIVE_TEXTURE: | |
| 564 #if defined(VIDEO_HOLE) | |
| 565 case VideoFrame::HOLE: | |
| 566 #endif // defined(VIDEO_HOLE) | |
| 567 break; | |
| 568 } | |
| 569 NOTREACHED() << "Unsupported video frame format/plane: " | |
| 570 << format << "/" << plane; | |
| 571 return gfx::Size(); | |
| 572 } | 567 } |
| 573 | 568 |
| 574 size_t VideoFrame::PlaneAllocationSize(Format format, | 569 size_t VideoFrame::PlaneAllocationSize(Format format, |
| 575 size_t plane, | 570 size_t plane, |
| 576 const gfx::Size& coded_size) { | 571 const gfx::Size& coded_size) { |
| 577 // VideoFrame formats are (so far) all YUV and 1 byte per sample. | 572 // VideoFrame formats are (so far) all YUV and 1 byte per sample. |
| 578 return PlaneSize(format, plane, coded_size).GetArea(); | 573 return PlaneSize(format, plane, coded_size).GetArea(); |
| 579 } | 574 } |
| 580 | 575 |
| 581 // static | 576 // static |
| 582 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) { | 577 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) { |
| 583 switch (format) { | 578 DCHECK(IsValidPlane(plane, format)); |
| 584 case VideoFrame::YV24: | 579 const int bits_per_element = 8 * BytesPerElement(format, plane); |
| 585 switch (plane) { | 580 const int pixels_per_element = SampleSize(format, plane).GetArea(); |
| 586 case kYPlane: | 581 DCHECK(bits_per_element % pixels_per_element == 0); |
| 587 case kUPlane: | 582 return bits_per_element / pixels_per_element; |
| 588 case kVPlane: | |
| 589 return 8; | |
| 590 default: | |
| 591 break; | |
| 592 } | |
| 593 break; | |
| 594 case VideoFrame::YV12: | |
| 595 case VideoFrame::YV16: | |
| 596 case VideoFrame::I420: | |
| 597 case VideoFrame::YV12J: | |
| 598 switch (plane) { | |
| 599 case kYPlane: | |
| 600 return 8; | |
| 601 case kUPlane: | |
| 602 case kVPlane: | |
| 603 return 2; | |
| 604 default: | |
| 605 break; | |
| 606 } | |
| 607 break; | |
| 608 case VideoFrame::YV12A: | |
| 609 switch (plane) { | |
| 610 case kYPlane: | |
| 611 case kAPlane: | |
| 612 return 8; | |
| 613 case kUPlane: | |
| 614 case kVPlane: | |
| 615 return 2; | |
| 616 default: | |
| 617 break; | |
| 618 } | |
| 619 break; | |
| 620 case VideoFrame::NV12: | |
| 621 switch (plane) { | |
| 622 case kYPlane: | |
| 623 return 8; | |
| 624 case kUVPlane: | |
| 625 return 4; | |
| 626 default: | |
| 627 break; | |
| 628 } | |
| 629 break; | |
| 630 case VideoFrame::UNKNOWN: | |
| 631 #if defined(VIDEO_HOLE) | |
| 632 case VideoFrame::HOLE: | |
| 633 #endif // defined(VIDEO_HOLE) | |
| 634 case VideoFrame::NATIVE_TEXTURE: | |
| 635 break; | |
| 636 } | |
| 637 NOTREACHED() << "Unsupported video frame format/plane: " | |
| 638 << format << "/" << plane; | |
| 639 return 0; | |
| 640 } | 583 } |
| 641 | 584 |
| 642 // Release data allocated by AllocateYUV(). | 585 // Release data allocated by AllocateYUV(). |
| 643 static void ReleaseData(uint8* data) { | 586 static void ReleaseData(uint8* data) { |
| 644 DCHECK(data); | 587 DCHECK(data); |
| 645 base::AlignedFree(data); | 588 base::AlignedFree(data); |
| 646 } | 589 } |
| 647 | 590 |
| 648 void VideoFrame::AllocateYUV() { | 591 void VideoFrame::AllocateYUV() { |
| 649 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 || | 592 DCHECK(format_ == YV12 || format_ == YV16 || format_ == YV12A || |
| 650 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 || | 593 format_ == I420 || format_ == YV12J || format_ == YV24); |
| 651 format_ == VideoFrame::YV12J || format_ == VideoFrame::YV24); | 594 COMPILE_ASSERT(0 == kYPlane, y_plane_data_must_be_index_0); |
| 652 // Align Y rows at least at 16 byte boundaries. The stride for both | |
| 653 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for | |
| 654 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in | |
| 655 // the case of YV12 the strides are identical for the same width surface, but | |
| 656 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as | |
| 657 // YV16. We also round the height of the surface allocated to be an even | |
| 658 // number to avoid any potential of faulting by code that attempts to access | |
| 659 // the Y values of the final row, but assumes that the last row of U & V | |
| 660 // applies to a full two rows of Y. YV12A is the same as YV12, but with an | |
| 661 // additional alpha plane that has the same size and alignment as the Y plane. | |
| 662 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), | |
| 663 kFrameSizeAlignment); | |
| 664 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), | |
| 665 kFrameSizeAlignment); | |
| 666 | 595 |
| 667 // The *2 here is because some formats (e.g. h264) allow interlaced coding, | 596 size_t data_size = 0; |
| 668 // and then the size needs to be a multiple of two macroblocks (vertically). | 597 size_t offset[kMaxPlanes]; |
| 669 // See libavcodec/utils.c:avcodec_align_dimensions2(). | 598 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane) { |
| 670 size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); | 599 // The *2 in alignment for height is because some formats (e.g. h264) allow |
| 671 size_t uv_height = | 600 // interlaced coding, and then the size needs to be a multiple of two |
| 672 (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A || | 601 // macroblocks (vertically). See |
| 673 format_ == VideoFrame::I420) | 602 // libavcodec/utils.c:avcodec_align_dimensions2(). |
| 674 ? y_height / 2 | 603 const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2); |
| 675 : y_height; | 604 strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment); |
| 676 size_t y_bytes = y_height * y_stride; | 605 offset[plane] = data_size; |
| 677 size_t uv_bytes = uv_height * uv_stride; | 606 data_size += height * strides_[plane]; |
| 678 size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0; | 607 } |
| 679 | 608 |
| 680 // The extra line of UV being allocated is because h264 chroma MC | 609 // The extra line of UV being allocated is because h264 chroma MC |
| 681 // overreads by one line in some cases, see libavcodec/utils.c: | 610 // overreads by one line in some cases, see libavcodec/utils.c: |
| 682 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: | 611 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: |
| 683 // put_h264_chroma_mc4_ssse3(). | 612 // put_h264_chroma_mc4_ssse3(). |
| 684 const size_t data_size = | 613 DCHECK(IsValidPlane(kUPlane, format_)); |
| 685 y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding; | 614 data_size += strides_[kUPlane] + kFrameSizePadding; |
| 615 | |
| 616 // FFmpeg expects the initialize allocation to be zero-initialized. Failure | |
| 617 // to do so can lead to unitialized value usage. See http://crbug.com/390941 | |
| 686 uint8* data = reinterpret_cast<uint8*>( | 618 uint8* data = reinterpret_cast<uint8*>( |
| 687 base::AlignedAlloc(data_size, kFrameAddressAlignment)); | 619 base::AlignedAlloc(data_size, kFrameAddressAlignment)); |
| 688 // FFmpeg expects the initialize allocation to be zero-initialized. Failure | |
| 689 // to do so can lead to unitialized value usage. See http://crbug.com/390941 | |
| 690 memset(data, 0, data_size); | 620 memset(data, 0, data_size); |
| 621 | |
| 622 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane) | |
| 623 data_[plane] = data + offset[plane]; | |
| 624 | |
| 691 no_longer_needed_cb_ = base::Bind(&ReleaseData, data); | 625 no_longer_needed_cb_ = base::Bind(&ReleaseData, data); |
| 692 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); | |
| 693 data_[VideoFrame::kYPlane] = data; | |
| 694 data_[VideoFrame::kUPlane] = data + y_bytes; | |
| 695 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; | |
| 696 strides_[VideoFrame::kYPlane] = y_stride; | |
| 697 strides_[VideoFrame::kUPlane] = uv_stride; | |
| 698 strides_[VideoFrame::kVPlane] = uv_stride; | |
| 699 if (format_ == YV12A) { | |
| 700 data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes); | |
| 701 strides_[VideoFrame::kAPlane] = y_stride; | |
| 702 } | |
| 703 } | 626 } |
| 704 | 627 |
| 705 VideoFrame::VideoFrame(VideoFrame::Format format, | 628 VideoFrame::VideoFrame(VideoFrame::Format format, |
| 706 const gfx::Size& coded_size, | 629 const gfx::Size& coded_size, |
| 707 const gfx::Rect& visible_rect, | 630 const gfx::Rect& visible_rect, |
| 708 const gfx::Size& natural_size, | 631 const gfx::Size& natural_size, |
| 709 scoped_ptr<gpu::MailboxHolder> mailbox_holder, | 632 scoped_ptr<gpu::MailboxHolder> mailbox_holder, |
| 710 base::TimeDelta timestamp, | 633 base::TimeDelta timestamp, |
| 711 bool end_of_stream) | 634 bool end_of_stream) |
| 712 : format_(format), | 635 : format_(format), |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 743 bool VideoFrame::IsValidPlane(size_t plane, VideoFrame::Format format) { | 666 bool VideoFrame::IsValidPlane(size_t plane, VideoFrame::Format format) { |
| 744 return (plane < NumPlanes(format)); | 667 return (plane < NumPlanes(format)); |
| 745 } | 668 } |
| 746 | 669 |
| 747 int VideoFrame::stride(size_t plane) const { | 670 int VideoFrame::stride(size_t plane) const { |
| 748 DCHECK(IsValidPlane(plane, format_)); | 671 DCHECK(IsValidPlane(plane, format_)); |
| 749 return strides_[plane]; | 672 return strides_[plane]; |
| 750 } | 673 } |
| 751 | 674 |
| 752 // static | 675 // static |
| 753 size_t VideoFrame::RowBytes(size_t plane, VideoFrame::Format format, | 676 size_t VideoFrame::RowBytes(size_t plane, |
| 677 VideoFrame::Format format, | |
| 754 int width) { | 678 int width) { |
| 755 DCHECK(IsValidPlane(plane, format)); | 679 DCHECK(IsValidPlane(plane, format)); |
| 756 switch (format) { | 680 return BytesPerElement(format, plane) * Columns(plane, format, width); |
| 757 case VideoFrame::YV24: | |
| 758 switch (plane) { | |
| 759 case kYPlane: | |
| 760 case kUPlane: | |
| 761 case kVPlane: | |
| 762 return width; | |
| 763 default: | |
| 764 break; | |
| 765 } | |
| 766 break; | |
| 767 case VideoFrame::YV12: | |
| 768 case VideoFrame::YV16: | |
| 769 case VideoFrame::I420: | |
| 770 case VideoFrame::YV12J: | |
| 771 switch (plane) { | |
| 772 case kYPlane: | |
| 773 return width; | |
| 774 case kUPlane: | |
| 775 case kVPlane: | |
| 776 return RoundUp(width, 2) / 2; | |
| 777 default: | |
| 778 break; | |
| 779 } | |
| 780 break; | |
| 781 case VideoFrame::YV12A: | |
| 782 switch (plane) { | |
| 783 case kYPlane: | |
| 784 case kAPlane: | |
| 785 return width; | |
| 786 case kUPlane: | |
| 787 case kVPlane: | |
| 788 return RoundUp(width, 2) / 2; | |
| 789 default: | |
| 790 break; | |
| 791 } | |
| 792 break; | |
| 793 case VideoFrame::NV12: | |
| 794 switch (plane) { | |
| 795 case kYPlane: | |
| 796 case kUVPlane: | |
| 797 return width; | |
| 798 default: | |
| 799 break; | |
| 800 } | |
| 801 break; | |
| 802 case VideoFrame::UNKNOWN: | |
| 803 #if defined(VIDEO_HOLE) | |
| 804 case VideoFrame::HOLE: | |
| 805 #endif // defined(VIDEO_HOLE) | |
| 806 case VideoFrame::NATIVE_TEXTURE: | |
| 807 break; | |
| 808 } | |
| 809 NOTREACHED() << "Unsupported video frame format/plane: " << format << "/" | |
| 810 << plane; | |
| 811 return 0; | |
| 812 } | 681 } |
| 813 | 682 |
| 814 int VideoFrame::row_bytes(size_t plane) const { | 683 int VideoFrame::row_bytes(size_t plane) const { |
| 815 return RowBytes(plane, format_, coded_size_.width()); | 684 return RowBytes(plane, format_, coded_size_.width()); |
| 816 } | 685 } |
| 817 | 686 |
| 818 // static | 687 // static |
| 819 size_t VideoFrame::Rows(size_t plane, VideoFrame::Format format, int height) { | 688 size_t VideoFrame::Rows(size_t plane, VideoFrame::Format format, int height) { |
| 820 DCHECK(IsValidPlane(plane, format)); | 689 DCHECK(IsValidPlane(plane, format)); |
| 821 switch (format) { | 690 const int sample_height = SampleSize(format, plane).height(); |
| 822 case VideoFrame::YV24: | 691 return RoundUp(height, sample_height) / sample_height; |
| 823 case VideoFrame::YV16: | 692 } |
| 824 switch (plane) { | 693 |
| 825 case kYPlane: | 694 // static |
| 826 case kUPlane: | 695 size_t VideoFrame::Columns(size_t plane, Format format, int width) { |
| 827 case kVPlane: | 696 DCHECK(IsValidPlane(plane, format)); |
| 828 return height; | 697 const int sample_width = SampleSize(format, plane).width(); |
| 829 default: | 698 return RoundUp(width, sample_width) / sample_width; |
| 830 break; | |
| 831 } | |
| 832 break; | |
| 833 case VideoFrame::YV12: | |
| 834 case VideoFrame::YV12J: | |
| 835 case VideoFrame::I420: | |
| 836 switch (plane) { | |
| 837 case kYPlane: | |
| 838 return height; | |
| 839 case kUPlane: | |
| 840 case kVPlane: | |
| 841 return RoundUp(height, 2) / 2; | |
| 842 default: | |
| 843 break; | |
| 844 } | |
| 845 break; | |
| 846 case VideoFrame::YV12A: | |
| 847 switch (plane) { | |
| 848 case kYPlane: | |
| 849 case kAPlane: | |
| 850 return height; | |
| 851 case kUPlane: | |
| 852 case kVPlane: | |
| 853 return RoundUp(height, 2) / 2; | |
| 854 default: | |
| 855 break; | |
| 856 } | |
| 857 break; | |
| 858 case VideoFrame::NV12: | |
| 859 switch (plane) { | |
| 860 case kYPlane: | |
| 861 return height; | |
| 862 case kUVPlane: | |
| 863 return RoundUp(height, 2) / 2; | |
| 864 default: | |
| 865 break; | |
| 866 } | |
| 867 break; | |
| 868 case VideoFrame::UNKNOWN: | |
| 869 #if defined(VIDEO_HOLE) | |
| 870 case VideoFrame::HOLE: | |
| 871 #endif // defined(VIDEO_HOLE) | |
| 872 case VideoFrame::NATIVE_TEXTURE: | |
| 873 break; | |
| 874 } | |
| 875 NOTREACHED() << "Unsupported video frame format/plane: " << format << "/" | |
| 876 << plane; | |
| 877 return 0; | |
| 878 } | 699 } |
| 879 | 700 |
| 880 int VideoFrame::rows(size_t plane) const { | 701 int VideoFrame::rows(size_t plane) const { |
| 881 return Rows(plane, format_, coded_size_.height()); | 702 return Rows(plane, format_, coded_size_.height()); |
| 882 } | 703 } |
| 883 | 704 |
| 884 uint8* VideoFrame::data(size_t plane) const { | 705 const uint8* VideoFrame::data(size_t plane) const { |
| 885 DCHECK(IsValidPlane(plane, format_)); | 706 DCHECK(IsValidPlane(plane, format_)); |
| 886 return data_[plane]; | 707 return data_[plane]; |
| 887 } | 708 } |
| 888 | 709 |
| 710 uint8* VideoFrame::data(size_t plane) { | |
| 711 DCHECK(IsValidPlane(plane, format_)); | |
| 712 return data_[plane]; | |
| 713 } | |
| 714 | |
| 715 const uint8* VideoFrame::visible_data(size_t plane) const { | |
| 716 DCHECK(IsValidPlane(plane, format_)); | |
| 717 | |
| 718 // Calculate an offset that is properly aligned for all planes. | |
| 719 const gfx::Size alignment = CommonAlignment(format_); | |
| 720 const gfx::Point offset(RoundDown(visible_rect_.x(), alignment.width()), | |
| 721 RoundDown(visible_rect_.y(), alignment.height())); | |
| 722 | |
| 723 const gfx::Size subsample = SampleSize(format_, plane); | |
| 724 DCHECK(offset.x() % subsample.width() == 0 && | |
| 725 offset.y() % subsample.height() == 0); | |
|
scherkus (not reviewing)
2014/10/22 23:01:50
ditto for DCHECK failure
magjed_chromium
2014/10/23 11:44:31
Done.
| |
| 726 return data(plane) + | |
| 727 stride(plane) * (offset.y() / subsample.height()) + // Row offset. | |
| 728 BytesPerElement(format_, plane) * // Column offset. | |
| 729 (offset.x() / subsample.width()); | |
| 730 } | |
| 731 | |
| 732 uint8* VideoFrame::visible_data(size_t plane) { | |
| 733 return const_cast<uint8*>( | |
| 734 static_cast<const VideoFrame*>(this)->visible_data(plane)); | |
| 735 } | |
| 736 | |
| 889 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const { | 737 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const { |
| 890 DCHECK_EQ(format_, NATIVE_TEXTURE); | 738 DCHECK_EQ(format_, NATIVE_TEXTURE); |
| 891 return mailbox_holder_.get(); | 739 return mailbox_holder_.get(); |
| 892 } | 740 } |
| 893 | 741 |
| 894 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const { | 742 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const { |
| 895 return shared_memory_handle_; | 743 return shared_memory_handle_; |
| 896 } | 744 } |
| 897 | 745 |
| 898 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) { | 746 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 912 } | 760 } |
| 913 #endif | 761 #endif |
| 914 | 762 |
| 915 #if defined(OS_MACOSX) | 763 #if defined(OS_MACOSX) |
| 916 CVPixelBufferRef VideoFrame::cv_pixel_buffer() const { | 764 CVPixelBufferRef VideoFrame::cv_pixel_buffer() const { |
| 917 return cv_pixel_buffer_.get(); | 765 return cv_pixel_buffer_.get(); |
| 918 } | 766 } |
| 919 #endif | 767 #endif |
| 920 | 768 |
| 921 void VideoFrame::HashFrameForTesting(base::MD5Context* context) { | 769 void VideoFrame::HashFrameForTesting(base::MD5Context* context) { |
| 922 for (int plane = 0; plane < kMaxPlanes; ++plane) { | 770 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) { |
| 923 if (!IsValidPlane(plane, format_)) | |
| 924 break; | |
| 925 for (int row = 0; row < rows(plane); ++row) { | 771 for (int row = 0; row < rows(plane); ++row) { |
| 926 base::MD5Update(context, base::StringPiece( | 772 base::MD5Update(context, base::StringPiece( |
| 927 reinterpret_cast<char*>(data(plane) + stride(plane) * row), | 773 reinterpret_cast<char*>(data(plane) + stride(plane) * row), |
| 928 row_bytes(plane))); | 774 row_bytes(plane))); |
| 929 } | 775 } |
| 930 } | 776 } |
| 931 } | 777 } |
| 932 | 778 |
| 933 } // namespace media | 779 } // namespace media |
| OLD | NEW |