OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 namespace media { |
| 8 |
| 9 // static |
| 10 void VideoFrame::CreateFrame(VideoFrame::Format format, |
| 11 size_t width, |
| 12 size_t height, |
| 13 base::TimeDelta timestamp, |
| 14 base::TimeDelta duration, |
| 15 scoped_refptr<VideoFrame>* frame_out) { |
| 16 DCHECK(width > 0 && height > 0); |
| 17 DCHECK(width * height < 100000000); |
| 18 DCHECK(frame_out); |
| 19 bool alloc_worked = false; |
| 20 scoped_refptr<VideoFrame> frame = |
| 21 new VideoFrame(format, width, height); |
| 22 if (frame) { |
| 23 frame->SetTimestamp(timestamp); |
| 24 frame->SetDuration(duration); |
| 25 switch (format) { |
| 26 case VideoFrame::RGB555: |
| 27 case VideoFrame::RGB565: |
| 28 alloc_worked = frame->AllocateRGB(2u); |
| 29 break; |
| 30 case VideoFrame::RGB24: |
| 31 alloc_worked = frame->AllocateRGB(3u); |
| 32 break; |
| 33 case VideoFrame::RGB32: |
| 34 case VideoFrame::RGBA: |
| 35 alloc_worked = frame->AllocateRGB(4u); |
| 36 break; |
| 37 case VideoFrame::YV12: |
| 38 case VideoFrame::YV16: |
| 39 alloc_worked = frame->AllocateYUV(); |
| 40 break; |
| 41 default: |
| 42 NOTREACHED(); |
| 43 alloc_worked = false; |
| 44 break; |
| 45 } |
| 46 } |
| 47 *frame_out = alloc_worked ? frame : NULL; |
| 48 } |
| 49 |
| 50 // static |
| 51 void VideoFrame::CreateEmptyFrame(scoped_refptr<VideoFrame>* frame_out) { |
| 52 *frame_out = new VideoFrame(VideoFrame::EMPTY, 0, 0); |
| 53 } |
| 54 |
| 55 // static |
| 56 void VideoFrame::CreateBlackFrame(int width, int height, |
| 57 scoped_refptr<VideoFrame>* frame_out) { |
| 58 DCHECK_GT(width, 0); |
| 59 DCHECK_GT(height, 0); |
| 60 |
| 61 // Create our frame. |
| 62 scoped_refptr<VideoFrame> frame; |
| 63 const base::TimeDelta kZero; |
| 64 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero, kZero, |
| 65 &frame); |
| 66 DCHECK(frame); |
| 67 |
| 68 // Now set the data to YUV(0,128,128). |
| 69 const uint8 kBlackY = 0x00; |
| 70 const uint8 kBlackUV = 0x80; |
| 71 |
| 72 // Fill the Y plane. |
| 73 uint8* y_plane = frame->data(VideoFrame::kYPlane); |
| 74 for (size_t i = 0; i < frame->height_; ++i) { |
| 75 memset(y_plane, kBlackY, frame->width_); |
| 76 y_plane += frame->stride(VideoFrame::kYPlane); |
| 77 } |
| 78 |
| 79 // Fill the U and V planes. |
| 80 uint8* u_plane = frame->data(VideoFrame::kUPlane); |
| 81 uint8* v_plane = frame->data(VideoFrame::kVPlane); |
| 82 for (size_t i = 0; i < (frame->height_ / 2); ++i) { |
| 83 memset(u_plane, kBlackUV, frame->width_ / 2); |
| 84 memset(v_plane, kBlackUV, frame->width_ / 2); |
| 85 u_plane += frame->stride(VideoFrame::kUPlane); |
| 86 v_plane += frame->stride(VideoFrame::kVPlane); |
| 87 } |
| 88 |
| 89 // Success! |
| 90 *frame_out = frame; |
| 91 } |
| 92 |
| 93 static inline size_t RoundUp(size_t value, size_t alignment) { |
| 94 // Check that |alignment| is a power of 2. |
| 95 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
| 96 return ((value + (alignment - 1)) & ~(alignment-1)); |
| 97 } |
| 98 |
| 99 bool VideoFrame::AllocateRGB(size_t bytes_per_pixel) { |
| 100 // Round up to align at a 64-bit (8 byte) boundary for each row. This |
| 101 // is sufficient for MMX reads (movq). |
| 102 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8); |
| 103 planes_ = VideoFrame::kNumRGBPlanes; |
| 104 strides_[VideoFrame::kRGBPlane] = bytes_per_row; |
| 105 data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_]; |
| 106 DCHECK(data_[VideoFrame::kRGBPlane]); |
| 107 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); |
| 108 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); |
| 109 return (NULL != data_[VideoFrame::kRGBPlane]); |
| 110 } |
| 111 |
| 112 bool VideoFrame::AllocateYUV() { |
| 113 DCHECK(format_ == VideoFrame::YV12 || |
| 114 format_ == VideoFrame::YV16); |
| 115 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and |
| 116 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V |
| 117 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the |
| 118 // case of YV12 the strides are identical for the same width surface, but the |
| 119 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16. |
| 120 // We also round the height of the surface allocated to be an even number |
| 121 // to avoid any potential of faulting by code that attempts to access the Y |
| 122 // values of the final row, but assumes that the last row of U & V applies to |
| 123 // a full two rows of Y. |
| 124 size_t alloc_height = RoundUp(height_, 2); |
| 125 size_t y_bytes_per_row = RoundUp(width_, 4); |
| 126 size_t uv_stride = RoundUp(y_bytes_per_row / 2, 4); |
| 127 size_t y_bytes = alloc_height * y_bytes_per_row; |
| 128 size_t uv_bytes = alloc_height * uv_stride; |
| 129 if (format_ == VideoFrame::YV12) { |
| 130 uv_bytes /= 2; |
| 131 } |
| 132 uint8* data = new uint8[y_bytes + (uv_bytes * 2)]; |
| 133 if (data) { |
| 134 planes_ = VideoFrame::kNumYUVPlanes; |
| 135 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); |
| 136 data_[VideoFrame::kYPlane] = data; |
| 137 data_[VideoFrame::kUPlane] = data + y_bytes; |
| 138 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; |
| 139 strides_[VideoFrame::kYPlane] = y_bytes_per_row; |
| 140 strides_[VideoFrame::kUPlane] = uv_stride; |
| 141 strides_[VideoFrame::kVPlane] = uv_stride; |
| 142 return true; |
| 143 } |
| 144 NOTREACHED(); |
| 145 return false; |
| 146 } |
| 147 |
| 148 VideoFrame::VideoFrame(VideoFrame::Format format, |
| 149 size_t width, |
| 150 size_t height) { |
| 151 format_ = format; |
| 152 width_ = width; |
| 153 height_ = height; |
| 154 planes_ = 0; |
| 155 memset(&strides_, 0, sizeof(strides_)); |
| 156 memset(&data_, 0, sizeof(data_)); |
| 157 } |
| 158 |
| 159 VideoFrame::~VideoFrame() { |
| 160 // In multi-plane allocations, only a single block of memory is allocated |
| 161 // on the heap, and other |data| pointers point inside the same, single block |
| 162 // so just delete index 0. |
| 163 delete[] data_[0]; |
| 164 } |
| 165 |
| 166 bool VideoFrame::IsEndOfStream() const { |
| 167 return format_ == VideoFrame::EMPTY; |
| 168 } |
| 169 |
| 170 } // namespace media |
OLD | NEW |