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 | |
11 | 14 |
12 namespace media { | 15 namespace media { |
13 | 16 |
14 // static | 17 // static |
15 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 18 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
16 VideoFrame::Format format, | 19 VideoFrame::Format format, |
17 size_t width, | 20 size_t width, |
18 size_t height, | 21 size_t height, |
22 size_t alignment, | |
19 base::TimeDelta timestamp, | 23 base::TimeDelta timestamp, |
20 base::TimeDelta duration) { | 24 base::TimeDelta duration) { |
21 DCHECK(IsValidConfig(format, width, height)); | 25 DCHECK(IsValidConfig(format, width, height, alignment)); |
22 scoped_refptr<VideoFrame> frame(new VideoFrame( | 26 scoped_refptr<VideoFrame> frame(new VideoFrame( |
23 format, width, height, timestamp, duration)); | 27 format, width, height, timestamp, duration)); |
24 switch (format) { | 28 switch (format) { |
25 case VideoFrame::RGB32: | 29 case VideoFrame::RGB32: |
26 frame->AllocateRGB(4u); | 30 frame->AllocateRGB(4u, alignment); |
scherkus (not reviewing)
2012/06/14 02:21:33
fix indent here
| |
27 break; | 31 break; |
28 case VideoFrame::YV12: | 32 case VideoFrame::YV12: |
29 case VideoFrame::YV16: | 33 case VideoFrame::YV16: |
30 frame->AllocateYUV(); | 34 frame->AllocateYUV(alignment); |
scherkus (not reviewing)
2012/06/14 02:21:33
fix indent here
| |
31 break; | 35 break; |
32 default: | 36 default: |
33 LOG(FATAL) << "Unsupported frame format: " << format; | 37 LOG(FATAL) << "Unsupported frame format: " << format; |
34 } | 38 } |
35 return frame; | 39 return frame; |
36 } | 40 } |
37 | 41 |
38 // static | 42 // static |
39 bool VideoFrame::IsValidConfig( | 43 bool VideoFrame::IsValidConfig( |
40 VideoFrame::Format format, | 44 VideoFrame::Format format, |
41 size_t width, | 45 size_t width, |
42 size_t height) { | 46 size_t height, |
47 size_t alignment) { | |
43 | 48 |
44 return (format != VideoFrame::INVALID && | 49 return (format != VideoFrame::INVALID && |
45 width > 0 && height > 0 && | 50 width > 0 && height > 0 && |
46 width <= limits::kMaxDimension && height <= limits::kMaxDimension && | 51 width <= limits::kMaxDimension && height <= limits::kMaxDimension && |
47 width * height <= limits::kMaxCanvas); | 52 width * height <= limits::kMaxCanvas && alignment > 0); |
scherkus (not reviewing)
2012/06/14 02:21:33
shouldn't alignment be checked for power of 2?
ch
| |
48 } | 53 } |
49 | 54 |
50 // static | 55 // static |
51 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( | 56 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( |
52 uint32 texture_id, | 57 uint32 texture_id, |
53 uint32 texture_target, | 58 uint32 texture_target, |
54 size_t width, | 59 size_t width, |
55 size_t height, | 60 size_t height, |
56 base::TimeDelta timestamp, | 61 base::TimeDelta timestamp, |
57 base::TimeDelta duration, | 62 base::TimeDelta duration, |
(...skipping 13 matching lines...) Expand all Loading... | |
71 } | 76 } |
72 | 77 |
73 // static | 78 // static |
74 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) { | 79 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) { |
75 DCHECK_GT(width, 0); | 80 DCHECK_GT(width, 0); |
76 DCHECK_GT(height, 0); | 81 DCHECK_GT(height, 0); |
77 | 82 |
78 // Create our frame. | 83 // Create our frame. |
79 const base::TimeDelta kZero; | 84 const base::TimeDelta kZero; |
80 scoped_refptr<VideoFrame> frame = | 85 scoped_refptr<VideoFrame> frame = |
81 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero, kZero); | 86 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, |
scherkus (not reviewing)
2012/06/14 02:21:33
revert change here
| |
87 kZero, kZero); | |
82 | 88 |
83 // Now set the data to YUV(0,128,128). | 89 // Now set the data to YUV(0,128,128). |
84 const uint8 kBlackY = 0x00; | 90 const uint8 kBlackY = 0x00; |
85 const uint8 kBlackUV = 0x80; | 91 const uint8 kBlackUV = 0x80; |
86 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); | 92 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); |
87 return frame; | 93 return frame; |
88 } | 94 } |
89 | 95 |
90 static inline size_t RoundUp(size_t value, size_t alignment) { | 96 static inline size_t RoundUp(size_t value, size_t alignment) { |
91 // Check that |alignment| is a power of 2. | 97 // Check that |alignment| is a power of 2. |
92 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | 98 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
93 return ((value + (alignment - 1)) & ~(alignment-1)); | 99 return ((value + (alignment - 1)) & ~(alignment-1)); |
94 } | 100 } |
95 | 101 |
96 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { | 102 static inline size_t Max(size_t a, size_t b) { |
scherkus (not reviewing)
2012/06/14 02:21:33
use std::max() instead?
| |
103 return a > b ? a : b; | |
104 } | |
105 | |
106 void VideoFrame::AllocateRGB(size_t bytes_per_pixel, size_t alignment) { | |
97 // Round up to align at a 64-bit (8 byte) boundary for each row. This | 107 // Round up to align at a 64-bit (8 byte) boundary for each row. This |
98 // is sufficient for MMX reads (movq). | 108 // is sufficient for MMX reads (movq). |
99 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8); | 109 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, Max(alignment, 8u)); |
110 size_t aligned_height = RoundUp(height_, alignment); | |
100 strides_[VideoFrame::kRGBPlane] = bytes_per_row; | 111 strides_[VideoFrame::kRGBPlane] = bytes_per_row; |
101 data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_]; | 112 #if !defined(OS_ANDROID) |
113 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be | |
scherkus (not reviewing)
2012/06/14 02:21:33
s/TODO/TODO(dalecurtis):/
| |
114 // repeated in every single user of aligned data. | |
115 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8 *>( | |
scherkus (not reviewing)
2012/06/14 02:21:33
pointers go w/ types
good: uint8* var
bad: uint8
| |
116 av_malloc(bytes_per_row * aligned_height)); | |
scherkus (not reviewing)
2012/06/14 02:21:33
4-space indent
| |
117 #else | |
118 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height]; | |
119 #endif | |
102 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); | 120 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); |
103 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); | 121 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); |
104 } | 122 } |
105 | 123 |
106 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert. | 124 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert. |
107 | 125 |
108 void VideoFrame::AllocateYUV() { | 126 void VideoFrame::AllocateYUV(size_t alignment) { |
109 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); | 127 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); |
110 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and | 128 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and |
111 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V | 129 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V |
112 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the | 130 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the |
113 // case of YV12 the strides are identical for the same width surface, but the | 131 // case of YV12 the strides are identical for the same width surface, but the |
114 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16. | 132 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16. |
115 // We also round the height of the surface allocated to be an even number | 133 // We also round the height of the surface allocated to be an even number |
116 // to avoid any potential of faulting by code that attempts to access the Y | 134 // to avoid any potential of faulting by code that attempts to access the Y |
117 // values of the final row, but assumes that the last row of U & V applies to | 135 // values of the final row, but assumes that the last row of U & V applies to |
118 // a full two rows of Y. | 136 // a full two rows of Y. |
scherkus (not reviewing)
2012/06/14 02:21:33
comment needs updating to say this does a minimum
| |
119 size_t y_height = rows(VideoFrame::kYPlane); | 137 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), |
120 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 4); | 138 Max(alignment, 4u)); |
121 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 4); | 139 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), |
122 size_t uv_height = rows(VideoFrame::kUPlane); | 140 Max(alignment, 4u)); |
141 size_t y_height = RoundUp(height_, Max(alignment, 2u)); | |
142 size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; | |
123 size_t y_bytes = y_height * y_stride; | 143 size_t y_bytes = y_height * y_stride; |
124 size_t uv_bytes = uv_height * uv_stride; | 144 size_t uv_bytes = uv_height * uv_stride; |
125 | 145 |
126 uint8* data = new uint8[y_bytes + (uv_bytes * 2) + kFramePadBytes]; | 146 #if !defined(OS_ANDROID) |
147 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be | |
scherkus (not reviewing)
2012/06/14 02:21:33
ditto
| |
148 // repeated in every single user of aligned data. | |
149 uint8* data = reinterpret_cast<uint8 *>( | |
scherkus (not reviewing)
2012/06/14 02:21:33
ditto for pointers
| |
150 av_malloc(y_bytes + (uv_bytes * 2) + kFramePadBytes)); | |
151 #else | |
152 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2) + kFramePadBytes]; | |
153 #endif | |
127 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); | 154 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); |
128 data_[VideoFrame::kYPlane] = data; | 155 data_[VideoFrame::kYPlane] = data; |
129 data_[VideoFrame::kUPlane] = data + y_bytes; | 156 data_[VideoFrame::kUPlane] = data + y_bytes; |
130 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; | 157 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; |
131 strides_[VideoFrame::kYPlane] = y_stride; | 158 strides_[VideoFrame::kYPlane] = y_stride; |
132 strides_[VideoFrame::kUPlane] = uv_stride; | 159 strides_[VideoFrame::kUPlane] = uv_stride; |
133 strides_[VideoFrame::kVPlane] = uv_stride; | 160 strides_[VideoFrame::kVPlane] = uv_stride; |
134 } | 161 } |
135 | 162 |
136 VideoFrame::VideoFrame(VideoFrame::Format format, | 163 VideoFrame::VideoFrame(VideoFrame::Format format, |
(...skipping 14 matching lines...) Expand all Loading... | |
151 | 178 |
152 VideoFrame::~VideoFrame() { | 179 VideoFrame::~VideoFrame() { |
153 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { | 180 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { |
154 texture_no_longer_needed_.Run(); | 181 texture_no_longer_needed_.Run(); |
155 texture_no_longer_needed_.Reset(); | 182 texture_no_longer_needed_.Reset(); |
156 } | 183 } |
157 | 184 |
158 // In multi-plane allocations, only a single block of memory is allocated | 185 // 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 | 186 // on the heap, and other |data| pointers point inside the same, single block |
160 // so just delete index 0. | 187 // so just delete index 0. |
161 delete[] data_[0]; | 188 if (data_[0]) { |
189 #if !defined(OS_ANDROID) | |
190 av_free(data_[0]); | |
191 #else | |
192 delete[] data_[0]; | |
193 #endif | |
194 } | |
162 } | 195 } |
163 | 196 |
164 bool VideoFrame::IsValidPlane(size_t plane) const { | 197 bool VideoFrame::IsValidPlane(size_t plane) const { |
165 switch (format_) { | 198 switch (format_) { |
166 case RGB32: | 199 case RGB32: |
167 return plane == kRGBPlane; | 200 return plane == kRGBPlane; |
168 | 201 |
169 case YV12: | 202 case YV12: |
170 case YV16: | 203 case YV16: |
171 return plane == kYPlane || plane == kUPlane || plane == kVPlane; | 204 return plane == kYPlane || plane == kUPlane || plane == kVPlane; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 break; | 290 break; |
258 for(int row = 0; row < rows(plane); row++) { | 291 for(int row = 0; row < rows(plane); row++) { |
259 base::MD5Update(context, base::StringPiece( | 292 base::MD5Update(context, base::StringPiece( |
260 reinterpret_cast<char*>(data(plane) + stride(plane) * row), | 293 reinterpret_cast<char*>(data(plane) + stride(plane) * row), |
261 row_bytes(plane))); | 294 row_bytes(plane))); |
262 } | 295 } |
263 } | 296 } |
264 } | 297 } |
265 | 298 |
266 } // namespace media | 299 } // namespace media |
OLD | NEW |