OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/common_video/include/video_frame_buffer.h" | 11 #include "webrtc/common_video/include/video_frame_buffer.h" |
12 | 12 |
13 #include "webrtc/base/checks.h" | 13 #include "webrtc/base/checks.h" |
14 #include "webrtc/base/keep_ref_until_done.h" | 14 #include "webrtc/base/keep_ref_until_done.h" |
15 #include "libyuv/convert.h" | 15 #include "libyuv/convert.h" |
16 | 16 |
17 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. | 17 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. |
18 static const int kBufferAlignment = 64; | 18 static const int kBufferAlignment = 64; |
19 | 19 |
20 namespace webrtc { | 20 namespace webrtc { |
21 | 21 |
22 namespace { | 22 namespace { |
23 | 23 |
24 int I420DataSize(int height, int stride_y, int stride_u, int stride_v) { | 24 int I420DataSize(int height, int stride_y, int stride_u, int stride_v) { |
25 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2); | 25 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2); |
26 } | 26 } |
27 | 27 |
28 } // namespace | 28 } // namespace |
29 | 29 |
30 uint8_t* VideoFrameBuffer::MutableData(PlaneType type) { | 30 const uint8_t* VideoFrameBuffer::data(PlaneType type) const { |
| 31 switch (type) { |
| 32 case kYPlane: |
| 33 return DataY(); |
| 34 case kUPlane: |
| 35 return DataU(); |
| 36 case kVPlane: |
| 37 return DataV(); |
| 38 default: |
| 39 RTC_NOTREACHED(); |
| 40 return nullptr; |
| 41 } |
| 42 } |
| 43 |
| 44 const uint8_t* VideoFrameBuffer::DataY() const { |
| 45 return data(kYPlane); |
| 46 } |
| 47 const uint8_t* VideoFrameBuffer::DataU() const { |
| 48 return data(kUPlane); |
| 49 } |
| 50 const uint8_t* VideoFrameBuffer::DataV() const { |
| 51 return data(kVPlane); |
| 52 } |
| 53 |
| 54 int VideoFrameBuffer::stride(PlaneType type) const { |
| 55 switch (type) { |
| 56 case kYPlane: |
| 57 return StrideY(); |
| 58 case kUPlane: |
| 59 return StrideU(); |
| 60 case kVPlane: |
| 61 return StrideV(); |
| 62 default: |
| 63 RTC_NOTREACHED(); |
| 64 return 0; |
| 65 } |
| 66 } |
| 67 |
| 68 int VideoFrameBuffer::StrideY() const { |
| 69 return stride(kYPlane); |
| 70 } |
| 71 int VideoFrameBuffer::StrideU() const { |
| 72 return stride(kUPlane); |
| 73 } |
| 74 int VideoFrameBuffer::StrideV() const { |
| 75 return stride(kVPlane); |
| 76 } |
| 77 |
| 78 uint8_t* VideoFrameBuffer::MutableDataY() { |
31 RTC_NOTREACHED(); | 79 RTC_NOTREACHED(); |
32 return nullptr; | 80 return nullptr; |
33 } | 81 } |
| 82 uint8_t* VideoFrameBuffer::MutableDataU() { |
| 83 RTC_NOTREACHED(); |
| 84 return nullptr; |
| 85 } |
| 86 uint8_t* VideoFrameBuffer::MutableDataV() { |
| 87 RTC_NOTREACHED(); |
| 88 return nullptr; |
| 89 } |
| 90 |
| 91 uint8_t* VideoFrameBuffer::MutableData(PlaneType type) { |
| 92 switch (type) { |
| 93 case kYPlane: |
| 94 return MutableDataY(); |
| 95 case kUPlane: |
| 96 return MutableDataU(); |
| 97 case kVPlane: |
| 98 return MutableDataV(); |
| 99 default: |
| 100 RTC_NOTREACHED(); |
| 101 return nullptr; |
| 102 } |
| 103 } |
34 | 104 |
35 VideoFrameBuffer::~VideoFrameBuffer() {} | 105 VideoFrameBuffer::~VideoFrameBuffer() {} |
36 | 106 |
37 I420Buffer::I420Buffer(int width, int height) | 107 I420Buffer::I420Buffer(int width, int height) |
38 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { | 108 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { |
39 } | 109 } |
40 | 110 |
41 I420Buffer::I420Buffer(int width, | 111 I420Buffer::I420Buffer(int width, |
42 int height, | 112 int height, |
43 int stride_y, | 113 int stride_y, |
(...skipping 23 matching lines...) Expand all Loading... |
67 } | 137 } |
68 | 138 |
69 int I420Buffer::width() const { | 139 int I420Buffer::width() const { |
70 return width_; | 140 return width_; |
71 } | 141 } |
72 | 142 |
73 int I420Buffer::height() const { | 143 int I420Buffer::height() const { |
74 return height_; | 144 return height_; |
75 } | 145 } |
76 | 146 |
77 const uint8_t* I420Buffer::data(PlaneType type) const { | 147 const uint8_t* I420Buffer::DataY() const { |
78 switch (type) { | 148 return data_.get(); |
79 case kYPlane: | 149 } |
80 return data_.get(); | 150 const uint8_t* I420Buffer::DataU() const { |
81 case kUPlane: | 151 return data_.get() + stride_y_ * height_; |
82 return data_.get() + stride_y_ * height_; | 152 } |
83 case kVPlane: | 153 const uint8_t* I420Buffer::DataV() const { |
84 return data_.get() + stride_y_ * height_ + | 154 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2); |
85 stride_u_ * ((height_ + 1) / 2); | |
86 default: | |
87 RTC_NOTREACHED(); | |
88 return nullptr; | |
89 } | |
90 } | 155 } |
91 | 156 |
92 bool I420Buffer::IsMutable() { | 157 bool I420Buffer::IsMutable() { |
93 return HasOneRef(); | 158 return HasOneRef(); |
94 } | 159 } |
95 | 160 |
96 uint8_t* I420Buffer::MutableData(PlaneType type) { | 161 uint8_t* I420Buffer::MutableDataY() { |
97 RTC_DCHECK(IsMutable()); | 162 RTC_DCHECK(IsMutable()); |
98 return const_cast<uint8_t*>( | 163 return const_cast<uint8_t*>(DataY()); |
99 static_cast<const VideoFrameBuffer*>(this)->data(type)); | 164 } |
| 165 uint8_t* I420Buffer::MutableDataU() { |
| 166 RTC_DCHECK(IsMutable()); |
| 167 return const_cast<uint8_t*>(DataU()); |
| 168 } |
| 169 uint8_t* I420Buffer::MutableDataV() { |
| 170 RTC_DCHECK(IsMutable()); |
| 171 return const_cast<uint8_t*>(DataV()); |
100 } | 172 } |
101 | 173 |
102 int I420Buffer::stride(PlaneType type) const { | 174 int I420Buffer::StrideY() const { |
103 switch (type) { | 175 return stride_y_; |
104 case kYPlane: | 176 } |
105 return stride_y_; | 177 int I420Buffer::StrideU() const { |
106 case kUPlane: | 178 return stride_u_; |
107 return stride_u_; | 179 } |
108 case kVPlane: | 180 int I420Buffer::StrideV() const { |
109 return stride_v_; | 181 return stride_v_; |
110 default: | |
111 RTC_NOTREACHED(); | |
112 return 0; | |
113 } | |
114 } | 182 } |
115 | 183 |
116 void* I420Buffer::native_handle() const { | 184 void* I420Buffer::native_handle() const { |
117 return nullptr; | 185 return nullptr; |
118 } | 186 } |
119 | 187 |
120 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { | 188 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { |
121 RTC_NOTREACHED(); | 189 RTC_NOTREACHED(); |
122 return nullptr; | 190 return nullptr; |
123 } | 191 } |
124 | 192 |
125 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( | 193 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( |
126 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) { | 194 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) { |
127 int width = buffer->width(); | 195 int width = buffer->width(); |
128 int height = buffer->height(); | 196 int height = buffer->height(); |
129 rtc::scoped_refptr<I420Buffer> copy = | 197 rtc::scoped_refptr<I420Buffer> copy = |
130 new rtc::RefCountedObject<I420Buffer>(width, height); | 198 new rtc::RefCountedObject<I420Buffer>(width, height); |
131 RTC_CHECK(libyuv::I420Copy(buffer->data(kYPlane), buffer->stride(kYPlane), | 199 RTC_CHECK(libyuv::I420Copy(buffer->DataY(), buffer->StrideY(), |
132 buffer->data(kUPlane), buffer->stride(kUPlane), | 200 buffer->DataU(), buffer->StrideU(), |
133 buffer->data(kVPlane), buffer->stride(kVPlane), | 201 buffer->DataV(), buffer->StrideV(), |
134 copy->MutableData(kYPlane), copy->stride(kYPlane), | 202 copy->MutableDataY(), copy->StrideY(), |
135 copy->MutableData(kUPlane), copy->stride(kUPlane), | 203 copy->MutableDataU(), copy->StrideU(), |
136 copy->MutableData(kVPlane), copy->stride(kVPlane), | 204 copy->MutableDataV(), copy->StrideV(), |
137 width, height) == 0); | 205 width, height) == 0); |
138 | 206 |
139 return copy; | 207 return copy; |
140 } | 208 } |
141 | 209 |
142 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, | 210 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, |
143 int width, | 211 int width, |
144 int height) | 212 int height) |
145 : native_handle_(native_handle), width_(width), height_(height) { | 213 : native_handle_(native_handle), width_(width), height_(height) { |
146 RTC_DCHECK(native_handle != nullptr); | 214 RTC_DCHECK(native_handle != nullptr); |
147 RTC_DCHECK_GT(width, 0); | 215 RTC_DCHECK_GT(width, 0); |
148 RTC_DCHECK_GT(height, 0); | 216 RTC_DCHECK_GT(height, 0); |
149 } | 217 } |
150 | 218 |
151 bool NativeHandleBuffer::IsMutable() { | 219 bool NativeHandleBuffer::IsMutable() { |
152 return false; | 220 return false; |
153 } | 221 } |
154 | 222 |
155 int NativeHandleBuffer::width() const { | 223 int NativeHandleBuffer::width() const { |
156 return width_; | 224 return width_; |
157 } | 225 } |
158 | 226 |
159 int NativeHandleBuffer::height() const { | 227 int NativeHandleBuffer::height() const { |
160 return height_; | 228 return height_; |
161 } | 229 } |
162 | 230 |
163 const uint8_t* NativeHandleBuffer::data(PlaneType type) const { | 231 const uint8_t* NativeHandleBuffer::DataY() const { |
| 232 RTC_NOTREACHED(); // Should not be called. |
| 233 return nullptr; |
| 234 } |
| 235 const uint8_t* NativeHandleBuffer::DataU() const { |
| 236 RTC_NOTREACHED(); // Should not be called. |
| 237 return nullptr; |
| 238 } |
| 239 const uint8_t* NativeHandleBuffer::DataV() const { |
164 RTC_NOTREACHED(); // Should not be called. | 240 RTC_NOTREACHED(); // Should not be called. |
165 return nullptr; | 241 return nullptr; |
166 } | 242 } |
167 | 243 |
168 int NativeHandleBuffer::stride(PlaneType type) const { | 244 int NativeHandleBuffer::StrideY() const { |
169 RTC_NOTREACHED(); // Should not be called. | 245 RTC_NOTREACHED(); // Should not be called. |
170 return 0; | 246 return 0; |
171 } | 247 } |
| 248 int NativeHandleBuffer::StrideU() const { |
| 249 RTC_NOTREACHED(); // Should not be called. |
| 250 return 0; |
| 251 } |
| 252 int NativeHandleBuffer::StrideV() const { |
| 253 RTC_NOTREACHED(); // Should not be called. |
| 254 return 0; |
| 255 } |
172 | 256 |
173 void* NativeHandleBuffer::native_handle() const { | 257 void* NativeHandleBuffer::native_handle() const { |
174 return native_handle_; | 258 return native_handle_; |
175 } | 259 } |
176 | 260 |
177 WrappedI420Buffer::WrappedI420Buffer(int width, | 261 WrappedI420Buffer::WrappedI420Buffer(int width, |
178 int height, | 262 int height, |
179 const uint8_t* y_plane, | 263 const uint8_t* y_plane, |
180 int y_stride, | 264 int y_stride, |
181 const uint8_t* u_plane, | 265 const uint8_t* u_plane, |
(...skipping 22 matching lines...) Expand all Loading... |
204 } | 288 } |
205 | 289 |
206 int WrappedI420Buffer::width() const { | 290 int WrappedI420Buffer::width() const { |
207 return width_; | 291 return width_; |
208 } | 292 } |
209 | 293 |
210 int WrappedI420Buffer::height() const { | 294 int WrappedI420Buffer::height() const { |
211 return height_; | 295 return height_; |
212 } | 296 } |
213 | 297 |
214 const uint8_t* WrappedI420Buffer::data(PlaneType type) const { | 298 const uint8_t* WrappedI420Buffer::DataY() const { |
215 switch (type) { | 299 return y_plane_; |
216 case kYPlane: | 300 } |
217 return y_plane_; | 301 const uint8_t* WrappedI420Buffer::DataU() const { |
218 case kUPlane: | 302 return u_plane_; |
219 return u_plane_; | 303 } |
220 case kVPlane: | 304 const uint8_t* WrappedI420Buffer::DataV() const { |
221 return v_plane_; | 305 return v_plane_; |
222 default: | |
223 RTC_NOTREACHED(); | |
224 return nullptr; | |
225 } | |
226 } | 306 } |
227 | 307 |
228 int WrappedI420Buffer::stride(PlaneType type) const { | 308 int WrappedI420Buffer::StrideY() const { |
229 switch (type) { | 309 return y_stride_; |
230 case kYPlane: | 310 } |
231 return y_stride_; | 311 int WrappedI420Buffer::StrideU() const { |
232 case kUPlane: | 312 return u_stride_; |
233 return u_stride_; | 313 } |
234 case kVPlane: | 314 int WrappedI420Buffer::StrideV() const { |
235 return v_stride_; | 315 return v_stride_; |
236 default: | |
237 RTC_NOTREACHED(); | |
238 return 0; | |
239 } | |
240 } | 316 } |
241 | 317 |
242 void* WrappedI420Buffer::native_handle() const { | 318 void* WrappedI420Buffer::native_handle() const { |
243 return nullptr; | 319 return nullptr; |
244 } | 320 } |
245 | 321 |
246 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { | 322 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { |
247 RTC_NOTREACHED(); | 323 RTC_NOTREACHED(); |
248 return nullptr; | 324 return nullptr; |
249 } | 325 } |
250 | 326 |
251 rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( | 327 rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( |
252 const rtc::scoped_refptr<VideoFrameBuffer>& buffer, | 328 const rtc::scoped_refptr<VideoFrameBuffer>& buffer, |
253 int cropped_width, | 329 int cropped_width, |
254 int cropped_height) { | 330 int cropped_height) { |
255 RTC_CHECK(buffer->native_handle() == nullptr); | 331 RTC_CHECK(buffer->native_handle() == nullptr); |
256 RTC_CHECK_LE(cropped_width, buffer->width()); | 332 RTC_CHECK_LE(cropped_width, buffer->width()); |
257 RTC_CHECK_LE(cropped_height, buffer->height()); | 333 RTC_CHECK_LE(cropped_height, buffer->height()); |
258 if (buffer->width() == cropped_width && buffer->height() == cropped_height) | 334 if (buffer->width() == cropped_width && buffer->height() == cropped_height) |
259 return buffer; | 335 return buffer; |
260 | 336 |
261 // Center crop to |cropped_width| x |cropped_height|. | 337 // Center crop to |cropped_width| x |cropped_height|. |
262 // Make sure offset is even so that u/v plane becomes aligned. | 338 // Make sure offset is even so that u/v plane becomes aligned. |
263 const int uv_offset_x = (buffer->width() - cropped_width) / 4; | 339 const int uv_offset_x = (buffer->width() - cropped_width) / 4; |
264 const int uv_offset_y = (buffer->height() - cropped_height) / 4; | 340 const int uv_offset_y = (buffer->height() - cropped_height) / 4; |
265 const int offset_x = uv_offset_x * 2; | 341 const int offset_x = uv_offset_x * 2; |
266 const int offset_y = uv_offset_y * 2; | 342 const int offset_y = uv_offset_y * 2; |
267 | 343 |
268 const uint8_t* y_plane = buffer->data(kYPlane) + | 344 const uint8_t* y_plane = buffer->DataY() + |
269 buffer->stride(kYPlane) * offset_y + offset_x; | 345 buffer->StrideY() * offset_y + offset_x; |
270 const uint8_t* u_plane = buffer->data(kUPlane) + | 346 const uint8_t* u_plane = buffer->DataU() + |
271 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x; | 347 buffer->StrideU() * uv_offset_y + uv_offset_x; |
272 const uint8_t* v_plane = buffer->data(kVPlane) + | 348 const uint8_t* v_plane = buffer->DataV() + |
273 buffer->stride(kVPlane) * uv_offset_y + uv_offset_x; | 349 buffer->StrideV() * uv_offset_y + uv_offset_x; |
274 return new rtc::RefCountedObject<WrappedI420Buffer>( | 350 return new rtc::RefCountedObject<WrappedI420Buffer>( |
275 cropped_width, cropped_height, | 351 cropped_width, cropped_height, |
276 y_plane, buffer->stride(kYPlane), | 352 y_plane, buffer->StrideY(), |
277 u_plane, buffer->stride(kUPlane), | 353 u_plane, buffer->StrideU(), |
278 v_plane, buffer->stride(kVPlane), | 354 v_plane, buffer->StrideV(), |
279 rtc::KeepRefUntilDone(buffer)); | 355 rtc::KeepRefUntilDone(buffer)); |
280 } | 356 } |
281 | 357 |
282 } // namespace webrtc | 358 } // namespace webrtc |
OLD | NEW |