| Index: media/base/video_frame.cc
|
| diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
|
| index 5f0d7282c6e01aedfe0861ee90e55e2cb319b7c1..abea883446669be3e88c1b27bf6c5a4a22d5a277 100644
|
| --- a/media/base/video_frame.cc
|
| +++ b/media/base/video_frame.cc
|
| @@ -14,6 +14,7 @@
|
| #include "gpu/command_buffer/common/mailbox_holder.h"
|
| #include "media/base/limits.h"
|
| #include "media/base/video_util.h"
|
| +#include "ui/gfx/point.h"
|
|
|
| #if !defined(MEDIA_FOR_CAST_IOS)
|
| #include "third_party/skia/include/core/SkBitmap.h"
|
| @@ -21,30 +22,84 @@
|
|
|
| namespace media {
|
|
|
| +static bool IsPowerOfTwo(size_t x) {
|
| + return x != 0 && (x & (x - 1)) == 0;
|
| +}
|
| +
|
| static inline size_t RoundUp(size_t value, size_t alignment) {
|
| - // Check that |alignment| is a power of 2.
|
| - DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
|
| + DCHECK(IsPowerOfTwo(alignment));
|
| return ((value + (alignment - 1)) & ~(alignment - 1));
|
| }
|
|
|
| +static inline size_t RoundDown(size_t value, size_t alignment) {
|
| + DCHECK(IsPowerOfTwo(alignment));
|
| + return value & ~(alignment - 1);
|
| +}
|
| +
|
| +// Returns the pixel size per element for given |plane| and |format|. E.g. 2x2
|
| +// for the U-plane in I420.
|
| +static gfx::Size SampleSize(VideoFrame::Format format, size_t plane) {
|
| + DCHECK(VideoFrame::IsValidPlane(plane, format));
|
| +
|
| + switch (plane) {
|
| + case VideoFrame::kYPlane:
|
| + case VideoFrame::kAPlane:
|
| + return gfx::Size(1, 1);
|
| +
|
| + case VideoFrame::kUPlane: // and VideoFrame::kUVPlane:
|
| + case VideoFrame::kVPlane:
|
| + switch (format) {
|
| + case VideoFrame::YV24:
|
| + return gfx::Size(1, 1);
|
| +
|
| + case VideoFrame::YV16:
|
| + return gfx::Size(2, 1);
|
| +
|
| + case VideoFrame::YV12:
|
| + case VideoFrame::YV12J:
|
| + case VideoFrame::I420:
|
| + case VideoFrame::YV12A:
|
| + case VideoFrame::NV12:
|
| + return gfx::Size(2, 2);
|
| +
|
| + case VideoFrame::UNKNOWN:
|
| +#if defined(VIDEO_HOLE)
|
| + case VideoFrame::HOLE:
|
| +#endif // defined(VIDEO_HOLE)
|
| + case VideoFrame::NATIVE_TEXTURE:
|
| + break;
|
| + }
|
| + }
|
| + NOTREACHED();
|
| + return gfx::Size();
|
| +}
|
| +
|
| +// Return the alignment for the whole frame, calculated as the max of the
|
| +// alignment for each individual plane.
|
| +static gfx::Size CommonAlignment(VideoFrame::Format format) {
|
| + int max_sample_width = 0;
|
| + int max_sample_height = 0;
|
| + for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) {
|
| + const gfx::Size sample_size = SampleSize(format, plane);
|
| + max_sample_width = std::max(max_sample_width, sample_size.width());
|
| + max_sample_height = std::max(max_sample_height, sample_size.height());
|
| + }
|
| + return gfx::Size(max_sample_width, max_sample_height);
|
| +}
|
| +
|
| +// Returns the number of bytes per element for given |plane| and |format|. E.g.
|
| +// 2 for the UV plane in NV12.
|
| +static int BytesPerElement(VideoFrame::Format format, size_t plane) {
|
| + DCHECK(VideoFrame::IsValidPlane(plane, format));
|
| + return (format == VideoFrame::NV12 && plane == VideoFrame::kUVPlane) ? 2 : 1;
|
| +}
|
| +
|
| // Rounds up |coded_size| if necessary for |format|.
|
| static gfx::Size AdjustCodedSize(VideoFrame::Format format,
|
| const gfx::Size& coded_size) {
|
| - gfx::Size new_coded_size(coded_size);
|
| - switch (format) {
|
| - case VideoFrame::YV12:
|
| - case VideoFrame::YV12A:
|
| - case VideoFrame::I420:
|
| - case VideoFrame::YV12J:
|
| - new_coded_size.set_height(RoundUp(new_coded_size.height(), 2));
|
| - // Fallthrough.
|
| - case VideoFrame::YV16:
|
| - new_coded_size.set_width(RoundUp(new_coded_size.width(), 2));
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - return new_coded_size;
|
| + const gfx::Size alignment = CommonAlignment(format);
|
| + return gfx::Size(RoundUp(coded_size.width(), alignment.width()),
|
| + RoundUp(coded_size.height(), alignment.height()));
|
| }
|
|
|
| // static
|
| @@ -64,7 +119,7 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
|
| // Since we're creating a new YUV frame (and allocating memory for it
|
| // ourselves), we can pad the requested |coded_size| if necessary if the
|
| // request does not line up on sample boundaries.
|
| - gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
| + const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
| DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
|
|
|
| scoped_refptr<VideoFrame> frame(
|
| @@ -131,35 +186,35 @@ bool VideoFrame::IsValidConfig(VideoFrame::Format format,
|
| case VideoFrame::UNKNOWN:
|
| return (coded_size.IsEmpty() && visible_rect.IsEmpty() &&
|
| natural_size.IsEmpty());
|
| +
|
| + // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
|
| + // allowed to skip the below check.
|
| + case VideoFrame::NATIVE_TEXTURE:
|
| +#if defined(VIDEO_HOLE)
|
| + case VideoFrame::HOLE:
|
| +#endif // defined(VIDEO_HOLE)
|
| + return true;
|
| +
|
| case VideoFrame::YV24:
|
| - break;
|
| case VideoFrame::YV12:
|
| case VideoFrame::YV12J:
|
| case VideoFrame::I420:
|
| case VideoFrame::YV12A:
|
| case VideoFrame::NV12:
|
| - // Subsampled YUV formats have width/height requirements.
|
| - if (static_cast<size_t>(coded_size.height()) <
|
| - RoundUp(visible_rect.bottom(), 2))
|
| - return false;
|
| - // Fallthrough.
|
| case VideoFrame::YV16:
|
| - if (static_cast<size_t>(coded_size.width()) <
|
| - RoundUp(visible_rect.right(), 2))
|
| - return false;
|
| - break;
|
| - case VideoFrame::NATIVE_TEXTURE:
|
| -#if defined(VIDEO_HOLE)
|
| - case VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
|
| - // allowed to skip the below check and be empty.
|
| - return true;
|
| + // Check that software-allocated buffer formats are aligned correctly and
|
| + // not empty.
|
| + const gfx::Size alignment = CommonAlignment(format);
|
| + return RoundUp(visible_rect.right(), alignment.width()) <=
|
| + static_cast<size_t>(coded_size.width()) &&
|
| + RoundUp(visible_rect.bottom(), alignment.height()) <=
|
| + static_cast<size_t>(coded_size.height()) &&
|
| + !coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
|
| + !natural_size.IsEmpty();
|
| }
|
|
|
| - // Check that software-allocated buffer formats are not empty.
|
| - return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
|
| - !natural_size.IsEmpty());
|
| + NOTREACHED();
|
| + return false;
|
| }
|
|
|
| // static
|
| @@ -203,7 +258,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
|
| base::SharedMemoryHandle handle,
|
| base::TimeDelta timestamp,
|
| const base::Closure& no_longer_needed_cb) {
|
| - gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
| + const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
|
|
| if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size))
|
| return NULL;
|
| @@ -291,7 +346,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer(
|
| DCHECK(cv_pixel_buffer);
|
| DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID());
|
|
|
| - OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer);
|
| + const OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer);
|
| Format format;
|
| // There are very few compatible CV pixel formats, so just check each.
|
| if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) {
|
| @@ -307,9 +362,9 @@ scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer(
|
| return NULL;
|
| }
|
|
|
| - gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer));
|
| - gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer));
|
| - gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer));
|
| + const gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer));
|
| + const gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer));
|
| + const gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer));
|
|
|
| if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
|
| return NULL;
|
| @@ -342,7 +397,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
|
| uint8* v_data,
|
| base::TimeDelta timestamp,
|
| const base::Closure& no_longer_needed_cb) {
|
| - gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
| + const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
|
| CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
|
|
|
| scoped_refptr<VideoFrame> frame(
|
| @@ -497,78 +552,19 @@ size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
|
| gfx::Size VideoFrame::PlaneSize(Format format,
|
| size_t plane,
|
| const gfx::Size& coded_size) {
|
| + DCHECK(IsValidPlane(plane, format));
|
| +
|
| // Align to multiple-of-two size overall. This ensures that non-subsampled
|
| // planes can be addressed by pixel with the same scaling as the subsampled
|
| // planes.
|
| const int width = RoundUp(coded_size.width(), 2);
|
| const int height = RoundUp(coded_size.height(), 2);
|
| - switch (format) {
|
| - case VideoFrame::YV24:
|
| - switch (plane) {
|
| - case VideoFrame::kYPlane:
|
| - case VideoFrame::kUPlane:
|
| - case VideoFrame::kVPlane:
|
| - return gfx::Size(width, height);
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12:
|
| - case VideoFrame::YV12J:
|
| - case VideoFrame::I420:
|
| - switch (plane) {
|
| - case VideoFrame::kYPlane:
|
| - return gfx::Size(width, height);
|
| - case VideoFrame::kUPlane:
|
| - case VideoFrame::kVPlane:
|
| - return gfx::Size(width / 2, height / 2);
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12A:
|
| - switch (plane) {
|
| - case VideoFrame::kYPlane:
|
| - case VideoFrame::kAPlane:
|
| - return gfx::Size(width, height);
|
| - case VideoFrame::kUPlane:
|
| - case VideoFrame::kVPlane:
|
| - return gfx::Size(width / 2, height / 2);
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV16:
|
| - switch (plane) {
|
| - case VideoFrame::kYPlane:
|
| - return gfx::Size(width, height);
|
| - case VideoFrame::kUPlane:
|
| - case VideoFrame::kVPlane:
|
| - return gfx::Size(width / 2, height);
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::NV12:
|
| - switch (plane) {
|
| - case VideoFrame::kYPlane:
|
| - return gfx::Size(width, height);
|
| - case VideoFrame::kUVPlane:
|
| - return gfx::Size(width, height / 2);
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::UNKNOWN:
|
| - case VideoFrame::NATIVE_TEXTURE:
|
| -#if defined(VIDEO_HOLE)
|
| - case VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - break;
|
| - }
|
| - NOTREACHED() << "Unsupported video frame format/plane: "
|
| - << format << "/" << plane;
|
| - return gfx::Size();
|
| +
|
| + const gfx::Size subsample = SampleSize(format, plane);
|
| + DCHECK(width % subsample.width() == 0);
|
| + DCHECK(height % subsample.height() == 0);
|
| + return gfx::Size(BytesPerElement(format, plane) * width / subsample.width(),
|
| + height / subsample.height());
|
| }
|
|
|
| size_t VideoFrame::PlaneAllocationSize(Format format,
|
| @@ -580,63 +576,11 @@ size_t VideoFrame::PlaneAllocationSize(Format format,
|
|
|
| // static
|
| int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) {
|
| - switch (format) {
|
| - case VideoFrame::YV24:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return 8;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12:
|
| - case VideoFrame::YV16:
|
| - case VideoFrame::I420:
|
| - case VideoFrame::YV12J:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - return 8;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12A:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kAPlane:
|
| - return 8;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::NV12:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - return 8;
|
| - case kUVPlane:
|
| - return 4;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::UNKNOWN:
|
| -#if defined(VIDEO_HOLE)
|
| - case VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - case VideoFrame::NATIVE_TEXTURE:
|
| - break;
|
| - }
|
| - NOTREACHED() << "Unsupported video frame format/plane: "
|
| - << format << "/" << plane;
|
| - return 0;
|
| + DCHECK(IsValidPlane(plane, format));
|
| + const int bits_per_element = 8 * BytesPerElement(format, plane);
|
| + const int pixels_per_element = SampleSize(format, plane).GetArea();
|
| + DCHECK(bits_per_element % pixels_per_element == 0);
|
| + return bits_per_element / pixels_per_element;
|
| }
|
|
|
| // Release data allocated by AllocateYUV().
|
| @@ -646,60 +590,40 @@ static void ReleaseData(uint8* data) {
|
| }
|
|
|
| void VideoFrame::AllocateYUV() {
|
| - DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
|
| - format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 ||
|
| - format_ == VideoFrame::YV12J || format_ == VideoFrame::YV24);
|
| - // Align Y rows at least at 16 byte boundaries. The stride for both
|
| - // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for
|
| - // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
|
| - // the case of YV12 the strides are identical for the same width surface, but
|
| - // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
|
| - // YV16. We also round the height of the surface allocated to be an even
|
| - // number to avoid any potential of faulting by code that attempts to access
|
| - // the Y values of the final row, but assumes that the last row of U & V
|
| - // applies to a full two rows of Y. YV12A is the same as YV12, but with an
|
| - // additional alpha plane that has the same size and alignment as the Y plane.
|
| - size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
|
| - kFrameSizeAlignment);
|
| - size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
|
| - kFrameSizeAlignment);
|
| -
|
| - // The *2 here is because some formats (e.g. h264) allow interlaced coding,
|
| - // and then the size needs to be a multiple of two macroblocks (vertically).
|
| - // See libavcodec/utils.c:avcodec_align_dimensions2().
|
| - size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
|
| - size_t uv_height =
|
| - (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
|
| - format_ == VideoFrame::I420)
|
| - ? y_height / 2
|
| - : y_height;
|
| - size_t y_bytes = y_height * y_stride;
|
| - size_t uv_bytes = uv_height * uv_stride;
|
| - size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
|
| + DCHECK(format_ == YV12 || format_ == YV16 || format_ == YV12A ||
|
| + format_ == I420 || format_ == YV12J || format_ == YV24);
|
| + COMPILE_ASSERT(0 == kYPlane, y_plane_data_must_be_index_0);
|
| +
|
| + size_t data_size = 0;
|
| + size_t offset[kMaxPlanes];
|
| + for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane) {
|
| + // The *2 in alignment for height is because some formats (e.g. h264) allow
|
| + // interlaced coding, and then the size needs to be a multiple of two
|
| + // macroblocks (vertically). See
|
| + // libavcodec/utils.c:avcodec_align_dimensions2().
|
| + const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2);
|
| + strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment);
|
| + offset[plane] = data_size;
|
| + data_size += height * strides_[plane];
|
| + }
|
|
|
| // The extra line of UV being allocated is because h264 chroma MC
|
| // overreads by one line in some cases, see libavcodec/utils.c:
|
| // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
|
| // put_h264_chroma_mc4_ssse3().
|
| - const size_t data_size =
|
| - y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding;
|
| - uint8* data = reinterpret_cast<uint8*>(
|
| - base::AlignedAlloc(data_size, kFrameAddressAlignment));
|
| + DCHECK(IsValidPlane(kUPlane, format_));
|
| + data_size += strides_[kUPlane] + kFrameSizePadding;
|
| +
|
| // FFmpeg expects the initialize allocation to be zero-initialized. Failure
|
| // to do so can lead to unitialized value usage. See http://crbug.com/390941
|
| + uint8* data = reinterpret_cast<uint8*>(
|
| + base::AlignedAlloc(data_size, kFrameAddressAlignment));
|
| memset(data, 0, data_size);
|
| +
|
| + for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane)
|
| + data_[plane] = data + offset[plane];
|
| +
|
| no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
|
| - COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
|
| - data_[VideoFrame::kYPlane] = data;
|
| - data_[VideoFrame::kUPlane] = data + y_bytes;
|
| - data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
|
| - strides_[VideoFrame::kYPlane] = y_stride;
|
| - strides_[VideoFrame::kUPlane] = uv_stride;
|
| - strides_[VideoFrame::kVPlane] = uv_stride;
|
| - if (format_ == YV12A) {
|
| - data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
|
| - strides_[VideoFrame::kAPlane] = y_stride;
|
| - }
|
| }
|
|
|
| VideoFrame::VideoFrame(VideoFrame::Format format,
|
| @@ -750,65 +674,11 @@ int VideoFrame::stride(size_t plane) const {
|
| }
|
|
|
| // static
|
| -size_t VideoFrame::RowBytes(size_t plane, VideoFrame::Format format,
|
| +size_t VideoFrame::RowBytes(size_t plane,
|
| + VideoFrame::Format format,
|
| int width) {
|
| DCHECK(IsValidPlane(plane, format));
|
| - switch (format) {
|
| - case VideoFrame::YV24:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return width;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12:
|
| - case VideoFrame::YV16:
|
| - case VideoFrame::I420:
|
| - case VideoFrame::YV12J:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - return width;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return RoundUp(width, 2) / 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12A:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kAPlane:
|
| - return width;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return RoundUp(width, 2) / 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::NV12:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kUVPlane:
|
| - return width;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::UNKNOWN:
|
| -#if defined(VIDEO_HOLE)
|
| - case VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - case VideoFrame::NATIVE_TEXTURE:
|
| - break;
|
| - }
|
| - NOTREACHED() << "Unsupported video frame format/plane: " << format << "/"
|
| - << plane;
|
| - return 0;
|
| + return BytesPerElement(format, plane) * Columns(plane, format, width);
|
| }
|
|
|
| int VideoFrame::row_bytes(size_t plane) const {
|
| @@ -818,74 +688,53 @@ int VideoFrame::row_bytes(size_t plane) const {
|
| // static
|
| size_t VideoFrame::Rows(size_t plane, VideoFrame::Format format, int height) {
|
| DCHECK(IsValidPlane(plane, format));
|
| - switch (format) {
|
| - case VideoFrame::YV24:
|
| - case VideoFrame::YV16:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return height;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12:
|
| - case VideoFrame::YV12J:
|
| - case VideoFrame::I420:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - return height;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return RoundUp(height, 2) / 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::YV12A:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - case kAPlane:
|
| - return height;
|
| - case kUPlane:
|
| - case kVPlane:
|
| - return RoundUp(height, 2) / 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::NV12:
|
| - switch (plane) {
|
| - case kYPlane:
|
| - return height;
|
| - case kUVPlane:
|
| - return RoundUp(height, 2) / 2;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case VideoFrame::UNKNOWN:
|
| -#if defined(VIDEO_HOLE)
|
| - case VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - case VideoFrame::NATIVE_TEXTURE:
|
| - break;
|
| - }
|
| - NOTREACHED() << "Unsupported video frame format/plane: " << format << "/"
|
| - << plane;
|
| - return 0;
|
| + const int sample_height = SampleSize(format, plane).height();
|
| + return RoundUp(height, sample_height) / sample_height;
|
| +}
|
| +
|
| +// static
|
| +size_t VideoFrame::Columns(size_t plane, Format format, int width) {
|
| + DCHECK(IsValidPlane(plane, format));
|
| + const int sample_width = SampleSize(format, plane).width();
|
| + return RoundUp(width, sample_width) / sample_width;
|
| }
|
|
|
| int VideoFrame::rows(size_t plane) const {
|
| return Rows(plane, format_, coded_size_.height());
|
| }
|
|
|
| -uint8* VideoFrame::data(size_t plane) const {
|
| +const uint8* VideoFrame::data(size_t plane) const {
|
| DCHECK(IsValidPlane(plane, format_));
|
| return data_[plane];
|
| }
|
|
|
| +uint8* VideoFrame::data(size_t plane) {
|
| + DCHECK(IsValidPlane(plane, format_));
|
| + return data_[plane];
|
| +}
|
| +
|
| +const uint8* VideoFrame::visible_data(size_t plane) const {
|
| + DCHECK(IsValidPlane(plane, format_));
|
| +
|
| + // Calculate an offset that is properly aligned for all planes.
|
| + const gfx::Size alignment = CommonAlignment(format_);
|
| + const gfx::Point offset(RoundDown(visible_rect_.x(), alignment.width()),
|
| + RoundDown(visible_rect_.y(), alignment.height()));
|
| +
|
| + const gfx::Size subsample = SampleSize(format_, plane);
|
| + DCHECK(offset.x() % subsample.width() == 0);
|
| + DCHECK(offset.y() % subsample.height() == 0);
|
| + return data(plane) +
|
| + stride(plane) * (offset.y() / subsample.height()) + // Row offset.
|
| + BytesPerElement(format_, plane) * // Column offset.
|
| + (offset.x() / subsample.width());
|
| +}
|
| +
|
| +uint8* VideoFrame::visible_data(size_t plane) {
|
| + return const_cast<uint8*>(
|
| + static_cast<const VideoFrame*>(this)->visible_data(plane));
|
| +}
|
| +
|
| const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
|
| DCHECK_EQ(format_, NATIVE_TEXTURE);
|
| return mailbox_holder_.get();
|
| @@ -919,9 +768,7 @@ CVPixelBufferRef VideoFrame::cv_pixel_buffer() const {
|
| #endif
|
|
|
| void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
|
| - for (int plane = 0; plane < kMaxPlanes; ++plane) {
|
| - if (!IsValidPlane(plane, format_))
|
| - break;
|
| + for (size_t plane = 0; plane < NumPlanes(format_); ++plane) {
|
| for (int row = 0; row < rows(plane); ++row) {
|
| base::MD5Update(context, base::StringPiece(
|
| reinterpret_cast<char*>(data(plane) + stride(plane) * row),
|
|
|