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 "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_piece.h" | 8 #include "base/string_piece.h" |
| 9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
| 10 #include "media/base/video_util.h" | 10 #include "media/base/video_util.h" |
| 11 #if !defined(OS_ANDROID) | |
| 12 #include "media/ffmpeg/ffmpeg_common.h" | |
| 13 #endif | |
| 14 | |
| 15 #include <algorithm> | |
| 11 | 16 |
| 12 namespace media { | 17 namespace media { |
| 13 | 18 |
| 14 // static | 19 // static |
| 15 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 20 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
| 16 VideoFrame::Format format, | 21 VideoFrame::Format format, |
| 17 size_t width, | 22 size_t width, |
| 18 size_t height, | 23 size_t height, |
| 19 base::TimeDelta timestamp, | 24 base::TimeDelta timestamp, |
| 20 base::TimeDelta duration) { | 25 base::TimeDelta duration) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); | 91 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); |
| 87 return frame; | 92 return frame; |
| 88 } | 93 } |
| 89 | 94 |
| 90 static inline size_t RoundUp(size_t value, size_t alignment) { | 95 static inline size_t RoundUp(size_t value, size_t alignment) { |
| 91 // Check that |alignment| is a power of 2. | 96 // Check that |alignment| is a power of 2. |
| 92 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | 97 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
| 93 return ((value + (alignment - 1)) & ~(alignment-1)); | 98 return ((value + (alignment - 1)) & ~(alignment-1)); |
| 94 } | 99 } |
| 95 | 100 |
| 101 static const int kFrameSizeAlignment = 16; | |
| 102 | |
| 96 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { | 103 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { |
| 97 // Round up to align at a 64-bit (8 byte) boundary for each row. This | 104 // Round up to align at least at a 64-bit (16 byte) boundary for each row. |
|
scherkus (not reviewing)
2012/06/18 20:27:38
64-bit != 16 bytes :)
Just say "align at 16 byte
| |
| 98 // is sufficient for MMX reads (movq). | 105 // This is sufficient for MMX reads (movq). |
| 99 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8); | 106 size_t bytes_per_row = RoundUp(width_, kFrameSizeAlignment) * bytes_per_pixel; |
| 107 size_t aligned_height = RoundUp(height_, kFrameSizeAlignment); | |
| 100 strides_[VideoFrame::kRGBPlane] = bytes_per_row; | 108 strides_[VideoFrame::kRGBPlane] = bytes_per_row; |
| 101 data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_]; | 109 #if !defined(OS_ANDROID) |
| 110 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery | |
| 111 // doesn't need to be repeated in every single user of aligned data. | |
| 112 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>( | |
| 113 av_malloc(bytes_per_row * aligned_height)); | |
| 114 #else | |
| 115 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height]; | |
| 116 #endif | |
| 102 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); | 117 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); |
| 103 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); | 118 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); |
| 104 } | 119 } |
| 105 | 120 |
| 106 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert. | |
| 107 | |
| 108 void VideoFrame::AllocateYUV() { | 121 void VideoFrame::AllocateYUV() { |
| 109 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); | 122 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); |
| 110 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and | 123 // Align Y rows at least at 16 byte boundaries. The stride for both |
| 111 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V | 124 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for |
| 112 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the | 125 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in |
| 113 // case of YV12 the strides are identical for the same width surface, but the | 126 // the case of YV12 the strides are identical for the same width surface, but |
| 114 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16. | 127 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as |
| 115 // We also round the height of the surface allocated to be an even number | 128 // YV16. We also round the height of the surface allocated to be an even |
| 116 // to avoid any potential of faulting by code that attempts to access the Y | 129 // number to avoid any potential of faulting by code that attempts to access |
| 117 // values of the final row, but assumes that the last row of U & V applies to | 130 // the Y values of the final row, but assumes that the last row of U & V |
| 118 // a full two rows of Y. | 131 // applies to a full two rows of Y. |
| 119 size_t y_height = rows(VideoFrame::kYPlane); | 132 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), |
| 120 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 4); | 133 kFrameSizeAlignment); |
| 121 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 4); | 134 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), |
| 122 size_t uv_height = rows(VideoFrame::kUPlane); | 135 kFrameSizeAlignment); |
| 136 size_t y_height = RoundUp(height_, kFrameSizeAlignment); | |
| 137 size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; | |
| 123 size_t y_bytes = y_height * y_stride; | 138 size_t y_bytes = y_height * y_stride; |
| 124 size_t uv_bytes = uv_height * uv_stride; | 139 size_t uv_bytes = uv_height * uv_stride; |
| 125 | 140 |
| 126 uint8* data = new uint8[y_bytes + (uv_bytes * 2) + kFramePadBytes]; | 141 #if !defined(OS_ANDROID) |
| 142 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery | |
| 143 // doesn't need to be repeated in every single user of aligned data. | |
| 144 uint8* data = reinterpret_cast<uint8*>( | |
| 145 av_malloc(y_bytes + (uv_bytes * 2))); | |
| 146 #else | |
| 147 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2)]; | |
| 148 #endif | |
| 127 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); | 149 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); |
| 128 data_[VideoFrame::kYPlane] = data; | 150 data_[VideoFrame::kYPlane] = data; |
| 129 data_[VideoFrame::kUPlane] = data + y_bytes; | 151 data_[VideoFrame::kUPlane] = data + y_bytes; |
| 130 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; | 152 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; |
| 131 strides_[VideoFrame::kYPlane] = y_stride; | 153 strides_[VideoFrame::kYPlane] = y_stride; |
| 132 strides_[VideoFrame::kUPlane] = uv_stride; | 154 strides_[VideoFrame::kUPlane] = uv_stride; |
| 133 strides_[VideoFrame::kVPlane] = uv_stride; | 155 strides_[VideoFrame::kVPlane] = uv_stride; |
| 134 } | 156 } |
| 135 | 157 |
| 136 VideoFrame::VideoFrame(VideoFrame::Format format, | 158 VideoFrame::VideoFrame(VideoFrame::Format format, |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 151 | 173 |
| 152 VideoFrame::~VideoFrame() { | 174 VideoFrame::~VideoFrame() { |
| 153 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { | 175 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { |
| 154 texture_no_longer_needed_.Run(); | 176 texture_no_longer_needed_.Run(); |
| 155 texture_no_longer_needed_.Reset(); | 177 texture_no_longer_needed_.Reset(); |
| 156 } | 178 } |
| 157 | 179 |
| 158 // In multi-plane allocations, only a single block of memory is allocated | 180 // In multi-plane allocations, only a single block of memory is allocated |
| 159 // on the heap, and other |data| pointers point inside the same, single block | 181 // on the heap, and other |data| pointers point inside the same, single block |
| 160 // so just delete index 0. | 182 // so just delete index 0. |
| 161 delete[] data_[0]; | 183 if (data_[0]) { |
| 184 #if !defined(OS_ANDROID) | |
| 185 av_free(data_[0]); | |
| 186 #else | |
| 187 delete[] data_[0]; | |
| 188 #endif | |
| 189 } | |
| 162 } | 190 } |
| 163 | 191 |
| 164 bool VideoFrame::IsValidPlane(size_t plane) const { | 192 bool VideoFrame::IsValidPlane(size_t plane) const { |
| 165 switch (format_) { | 193 switch (format_) { |
| 166 case RGB32: | 194 case RGB32: |
| 167 return plane == kRGBPlane; | 195 return plane == kRGBPlane; |
| 168 | 196 |
| 169 case YV12: | 197 case YV12: |
| 170 case YV16: | 198 case YV16: |
| 171 return plane == kYPlane || plane == kUPlane || plane == kVPlane; | 199 return plane == kYPlane || plane == kUPlane || plane == kVPlane; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 break; | 285 break; |
| 258 for(int row = 0; row < rows(plane); row++) { | 286 for(int row = 0; row < rows(plane); row++) { |
| 259 base::MD5Update(context, base::StringPiece( | 287 base::MD5Update(context, base::StringPiece( |
| 260 reinterpret_cast<char*>(data(plane) + stride(plane) * row), | 288 reinterpret_cast<char*>(data(plane) + stride(plane) * row), |
| 261 row_bytes(plane))); | 289 row_bytes(plane))); |
| 262 } | 290 } |
| 263 } | 291 } |
| 264 } | 292 } |
| 265 | 293 |
| 266 } // namespace media | 294 } // namespace media |
| OLD | NEW |