| Index: media/base/video_frame.cc
|
| ===================================================================
|
| --- media/base/video_frame.cc (revision 140753)
|
| +++ media/base/video_frame.cc (working copy)
|
| @@ -8,26 +8,46 @@
|
| #include "base/string_piece.h"
|
| #include "media/base/limits.h"
|
| #include "media/base/video_util.h"
|
| +#if !defined(OS_ANDROID)
|
| +#include "media/ffmpeg/ffmpeg_common.h"
|
| +#endif
|
|
|
| namespace media {
|
|
|
| +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)));
|
| + return ((value + (alignment - 1)) & ~(alignment-1));
|
| +}
|
| +
|
| // static
|
| scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
|
| VideoFrame::Format format,
|
| size_t width,
|
| size_t height,
|
| + size_t bytes_per_row,
|
| + size_t bytes_per_uv_row,
|
| + size_t aligned_height,
|
| base::TimeDelta timestamp,
|
| base::TimeDelta duration) {
|
| - DCHECK(IsValidConfig(format, width, height));
|
| + DCHECK(IsValidConfig(format, width, height, bytes_per_row, bytes_per_uv_row,
|
| + aligned_height));
|
| scoped_refptr<VideoFrame> frame(new VideoFrame(
|
| format, width, height, timestamp, duration));
|
| switch (format) {
|
| case VideoFrame::RGB32:
|
| - frame->AllocateRGB(4u);
|
| + frame->AllocateRGB(bytes_per_row ? bytes_per_row :
|
| + RoundUp(frame->row_bytes(VideoFrame::kRGBPlane),
|
| + 8),
|
| + aligned_height ? aligned_height : height);
|
| break;
|
| case VideoFrame::YV12:
|
| case VideoFrame::YV16:
|
| - frame->AllocateYUV();
|
| + frame->AllocateYUV(bytes_per_row ? bytes_per_row :
|
| + RoundUp(frame->row_bytes(VideoFrame::kYPlane), 4),
|
| + bytes_per_uv_row ? bytes_per_uv_row :
|
| + RoundUp(frame->row_bytes(VideoFrame::kUPlane), 4),
|
| + aligned_height ? aligned_height : height);
|
| break;
|
| default:
|
| LOG(FATAL) << "Unsupported frame format: " << format;
|
| @@ -39,12 +59,35 @@
|
| bool VideoFrame::IsValidConfig(
|
| VideoFrame::Format format,
|
| size_t width,
|
| - size_t height) {
|
| + size_t height,
|
| + size_t bytes_per_row,
|
| + size_t bytes_per_uv_row,
|
| + size_t aligned_height) {
|
|
|
| - return (format != VideoFrame::INVALID &&
|
| - width > 0 && height > 0 &&
|
| - width <= limits::kMaxDimension && height <= limits::kMaxDimension &&
|
| - width * height <= limits::kMaxCanvas);
|
| + if (!(format != VideoFrame::INVALID &&
|
| + width > 0 && height > 0 &&
|
| + width <= limits::kMaxDimension && height <= limits::kMaxDimension &&
|
| + width * height <= limits::kMaxCanvas))
|
| + return false;
|
| +
|
| + switch (format) {
|
| + case VideoFrame::RGB32:
|
| + if ((bytes_per_row != 0 && bytes_per_row < width) ||
|
| + (aligned_height != 0 && aligned_height < height))
|
| + return false;
|
| + break;
|
| + case VideoFrame::YV12:
|
| + case VideoFrame::YV16:
|
| + if ((bytes_per_row != 0 && bytes_per_row < width) ||
|
| + (bytes_per_uv_row != 0 && bytes_per_uv_row < RoundUp(width, 2) / 2) ||
|
| + (aligned_height != 0 && aligned_height < height))
|
| + return false;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| // static
|
| @@ -78,7 +121,8 @@
|
| // Create our frame.
|
| const base::TimeDelta kZero;
|
| scoped_refptr<VideoFrame> frame =
|
| - VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero, kZero);
|
| + VideoFrame::CreateFrame(VideoFrame::YV12, width, height,
|
| + 0, 0, 0, kZero, kZero);
|
|
|
| // Now set the data to YUV(0,128,128).
|
| const uint8 kBlackY = 0x00;
|
| @@ -87,25 +131,26 @@
|
| return frame;
|
| }
|
|
|
| -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)));
|
| - return ((value + (alignment - 1)) & ~(alignment-1));
|
| -}
|
| -
|
| -void VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
|
| +void VideoFrame::AllocateRGB(size_t bytes_per_row, size_t aligned_height) {
|
| // Round up to align at a 64-bit (8 byte) boundary for each row. This
|
| // is sufficient for MMX reads (movq).
|
| - size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8);
|
| strides_[VideoFrame::kRGBPlane] = bytes_per_row;
|
| - data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_];
|
| +#if !defined(OS_ANDROID)
|
| + // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
|
| + // repeated in every single user of aligned data.
|
| + data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8 *>(
|
| + av_malloc(bytes_per_row * aligned_height));
|
| +#else
|
| + data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height];
|
| +#endif
|
| DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
|
| COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
|
| }
|
|
|
| static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert.
|
|
|
| -void VideoFrame::AllocateYUV() {
|
| +void VideoFrame::AllocateYUV(size_t y_stride, size_t uv_stride,
|
| + size_t aligned_height) {
|
| DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16);
|
| // Align Y rows at 32-bit (4 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
|
| @@ -116,14 +161,20 @@
|
| // 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.
|
| - size_t y_height = rows(VideoFrame::kYPlane);
|
| - size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 4);
|
| - size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 4);
|
| - size_t uv_height = rows(VideoFrame::kUPlane);
|
| + size_t y_height = aligned_height;
|
| + size_t uv_height = format_ == VideoFrame::YV12 ?
|
| + RoundUp(aligned_height, 2) / 2 : aligned_height;
|
| size_t y_bytes = y_height * y_stride;
|
| size_t uv_bytes = uv_height * uv_stride;
|
|
|
| - uint8* data = new uint8[y_bytes + (uv_bytes * 2) + kFramePadBytes];
|
| +#if !defined(OS_ANDROID)
|
| + // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
|
| + // repeated in every single user of aligned data.
|
| + uint8* data = reinterpret_cast<uint8 *>(
|
| + av_malloc(y_bytes + (uv_bytes * 2) + kFramePadBytes));
|
| +#else
|
| + uint8* data = new uint8_t[y_bytes + (uv_bytes * 2) + kFramePadBytes];
|
| +#endif
|
| COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
|
| data_[VideoFrame::kYPlane] = data;
|
| data_[VideoFrame::kUPlane] = data + y_bytes;
|
| @@ -158,7 +209,13 @@
|
| // In multi-plane allocations, only a single block of memory is allocated
|
| // on the heap, and other |data| pointers point inside the same, single block
|
| // so just delete index 0.
|
| - delete[] data_[0];
|
| + if (data_[0]) {
|
| +#if !defined(OS_ANDROID)
|
| + av_free(data_[0]);
|
| +#else
|
| + delete[] data_[0];
|
| +#endif
|
| + }
|
| }
|
|
|
| bool VideoFrame::IsValidPlane(size_t plane) const {
|
|
|