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 int VideoFrameBuffer::stride(PlaneType type) const { |
| 45 switch (type) { |
| 46 case kYPlane: |
| 47 return StrideY(); |
| 48 case kUPlane: |
| 49 return StrideU(); |
| 50 case kVPlane: |
| 51 return StrideV(); |
| 52 default: |
| 53 RTC_NOTREACHED(); |
| 54 return 0; |
| 55 } |
| 56 } |
| 57 |
| 58 uint8_t* VideoFrameBuffer::MutableDataY() { |
31 RTC_NOTREACHED(); | 59 RTC_NOTREACHED(); |
32 return nullptr; | 60 return nullptr; |
33 } | 61 } |
| 62 uint8_t* VideoFrameBuffer::MutableDataU() { |
| 63 RTC_NOTREACHED(); |
| 64 return nullptr; |
| 65 } |
| 66 uint8_t* VideoFrameBuffer::MutableDataV() { |
| 67 RTC_NOTREACHED(); |
| 68 return nullptr; |
| 69 } |
| 70 |
| 71 uint8_t* VideoFrameBuffer::MutableData(PlaneType type) { |
| 72 switch (type) { |
| 73 case kYPlane: |
| 74 return MutableDataY(); |
| 75 case kUPlane: |
| 76 return MutableDataU(); |
| 77 case kVPlane: |
| 78 return MutableDataV(); |
| 79 default: |
| 80 RTC_NOTREACHED(); |
| 81 return nullptr; |
| 82 } |
| 83 } |
34 | 84 |
35 VideoFrameBuffer::~VideoFrameBuffer() {} | 85 VideoFrameBuffer::~VideoFrameBuffer() {} |
36 | 86 |
37 I420Buffer::I420Buffer(int width, int height) | 87 I420Buffer::I420Buffer(int width, int height) |
38 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { | 88 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { |
39 } | 89 } |
40 | 90 |
41 I420Buffer::I420Buffer(int width, | 91 I420Buffer::I420Buffer(int width, |
42 int height, | 92 int height, |
43 int stride_y, | 93 int stride_y, |
(...skipping 23 matching lines...) Expand all Loading... |
67 } | 117 } |
68 | 118 |
69 int I420Buffer::width() const { | 119 int I420Buffer::width() const { |
70 return width_; | 120 return width_; |
71 } | 121 } |
72 | 122 |
73 int I420Buffer::height() const { | 123 int I420Buffer::height() const { |
74 return height_; | 124 return height_; |
75 } | 125 } |
76 | 126 |
77 const uint8_t* I420Buffer::data(PlaneType type) const { | 127 const uint8_t* I420Buffer::DataY() const { |
78 switch (type) { | 128 return data_.get(); |
79 case kYPlane: | 129 } |
80 return data_.get(); | 130 const uint8_t* I420Buffer::DataU() const { |
81 case kUPlane: | 131 return data_.get() + stride_y_ * height_; |
82 return data_.get() + stride_y_ * height_; | 132 } |
83 case kVPlane: | 133 const uint8_t* I420Buffer::DataV() const { |
84 return data_.get() + stride_y_ * height_ + | 134 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 } | 135 } |
91 | 136 |
92 uint8_t* I420Buffer::MutableData(PlaneType type) { | 137 uint8_t* I420Buffer::MutableDataY() { |
93 RTC_DCHECK(HasOneRef()); | 138 RTC_DCHECK(HasOneRef()); |
94 return const_cast<uint8_t*>( | 139 return const_cast<uint8_t*>(DataY()); |
95 static_cast<const VideoFrameBuffer*>(this)->data(type)); | 140 } |
| 141 uint8_t* I420Buffer::MutableDataU() { |
| 142 RTC_DCHECK(HasOneRef()); |
| 143 return const_cast<uint8_t*>(DataU()); |
| 144 } |
| 145 uint8_t* I420Buffer::MutableDataV() { |
| 146 RTC_DCHECK(HasOneRef()); |
| 147 return const_cast<uint8_t*>(DataV()); |
96 } | 148 } |
97 | 149 |
98 int I420Buffer::stride(PlaneType type) const { | 150 int I420Buffer::StrideY() const { |
99 switch (type) { | 151 return stride_y_; |
100 case kYPlane: | 152 } |
101 return stride_y_; | 153 int I420Buffer::StrideU() const { |
102 case kUPlane: | 154 return stride_u_; |
103 return stride_u_; | 155 } |
104 case kVPlane: | 156 int I420Buffer::StrideV() const { |
105 return stride_v_; | 157 return stride_v_; |
106 default: | |
107 RTC_NOTREACHED(); | |
108 return 0; | |
109 } | |
110 } | 158 } |
111 | 159 |
112 void* I420Buffer::native_handle() const { | 160 void* I420Buffer::native_handle() const { |
113 return nullptr; | 161 return nullptr; |
114 } | 162 } |
115 | 163 |
116 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { | 164 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { |
117 RTC_NOTREACHED(); | 165 RTC_NOTREACHED(); |
118 return nullptr; | 166 return nullptr; |
119 } | 167 } |
120 | 168 |
121 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( | 169 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( |
122 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) { | 170 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) { |
123 int width = buffer->width(); | 171 int width = buffer->width(); |
124 int height = buffer->height(); | 172 int height = buffer->height(); |
125 rtc::scoped_refptr<I420Buffer> copy = | 173 rtc::scoped_refptr<I420Buffer> copy = |
126 new rtc::RefCountedObject<I420Buffer>(width, height); | 174 new rtc::RefCountedObject<I420Buffer>(width, height); |
127 RTC_CHECK(libyuv::I420Copy(buffer->data(kYPlane), buffer->stride(kYPlane), | 175 RTC_CHECK(libyuv::I420Copy(buffer->DataY(), buffer->StrideY(), |
128 buffer->data(kUPlane), buffer->stride(kUPlane), | 176 buffer->DataU(), buffer->StrideU(), |
129 buffer->data(kVPlane), buffer->stride(kVPlane), | 177 buffer->DataV(), buffer->StrideV(), |
130 copy->MutableData(kYPlane), copy->stride(kYPlane), | 178 copy->MutableDataY(), copy->StrideY(), |
131 copy->MutableData(kUPlane), copy->stride(kUPlane), | 179 copy->MutableDataU(), copy->StrideU(), |
132 copy->MutableData(kVPlane), copy->stride(kVPlane), | 180 copy->MutableDataV(), copy->StrideV(), |
133 width, height) == 0); | 181 width, height) == 0); |
134 | 182 |
135 return copy; | 183 return copy; |
136 } | 184 } |
137 | 185 |
138 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, | 186 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, |
139 int width, | 187 int width, |
140 int height) | 188 int height) |
141 : native_handle_(native_handle), width_(width), height_(height) { | 189 : native_handle_(native_handle), width_(width), height_(height) { |
142 RTC_DCHECK(native_handle != nullptr); | 190 RTC_DCHECK(native_handle != nullptr); |
143 RTC_DCHECK_GT(width, 0); | 191 RTC_DCHECK_GT(width, 0); |
144 RTC_DCHECK_GT(height, 0); | 192 RTC_DCHECK_GT(height, 0); |
145 } | 193 } |
146 | 194 |
147 int NativeHandleBuffer::width() const { | 195 int NativeHandleBuffer::width() const { |
148 return width_; | 196 return width_; |
149 } | 197 } |
150 | 198 |
151 int NativeHandleBuffer::height() const { | 199 int NativeHandleBuffer::height() const { |
152 return height_; | 200 return height_; |
153 } | 201 } |
154 | 202 |
155 const uint8_t* NativeHandleBuffer::data(PlaneType type) const { | 203 const uint8_t* NativeHandleBuffer::DataY() const { |
| 204 RTC_NOTREACHED(); // Should not be called. |
| 205 return nullptr; |
| 206 } |
| 207 const uint8_t* NativeHandleBuffer::DataU() const { |
| 208 RTC_NOTREACHED(); // Should not be called. |
| 209 return nullptr; |
| 210 } |
| 211 const uint8_t* NativeHandleBuffer::DataV() const { |
156 RTC_NOTREACHED(); // Should not be called. | 212 RTC_NOTREACHED(); // Should not be called. |
157 return nullptr; | 213 return nullptr; |
158 } | 214 } |
159 | 215 |
160 int NativeHandleBuffer::stride(PlaneType type) const { | 216 int NativeHandleBuffer::StrideY() const { |
161 RTC_NOTREACHED(); // Should not be called. | 217 RTC_NOTREACHED(); // Should not be called. |
162 return 0; | 218 return 0; |
163 } | 219 } |
| 220 int NativeHandleBuffer::StrideU() const { |
| 221 RTC_NOTREACHED(); // Should not be called. |
| 222 return 0; |
| 223 } |
| 224 int NativeHandleBuffer::StrideV() const { |
| 225 RTC_NOTREACHED(); // Should not be called. |
| 226 return 0; |
| 227 } |
164 | 228 |
165 void* NativeHandleBuffer::native_handle() const { | 229 void* NativeHandleBuffer::native_handle() const { |
166 return native_handle_; | 230 return native_handle_; |
167 } | 231 } |
168 | 232 |
169 WrappedI420Buffer::WrappedI420Buffer(int width, | 233 WrappedI420Buffer::WrappedI420Buffer(int width, |
170 int height, | 234 int height, |
171 const uint8_t* y_plane, | 235 const uint8_t* y_plane, |
172 int y_stride, | 236 int y_stride, |
173 const uint8_t* u_plane, | 237 const uint8_t* u_plane, |
(...skipping 17 matching lines...) Expand all Loading... |
191 } | 255 } |
192 | 256 |
193 int WrappedI420Buffer::width() const { | 257 int WrappedI420Buffer::width() const { |
194 return width_; | 258 return width_; |
195 } | 259 } |
196 | 260 |
197 int WrappedI420Buffer::height() const { | 261 int WrappedI420Buffer::height() const { |
198 return height_; | 262 return height_; |
199 } | 263 } |
200 | 264 |
201 const uint8_t* WrappedI420Buffer::data(PlaneType type) const { | 265 const uint8_t* WrappedI420Buffer::DataY() const { |
202 switch (type) { | 266 return y_plane_; |
203 case kYPlane: | 267 } |
204 return y_plane_; | 268 const uint8_t* WrappedI420Buffer::DataU() const { |
205 case kUPlane: | 269 return u_plane_; |
206 return u_plane_; | 270 } |
207 case kVPlane: | 271 const uint8_t* WrappedI420Buffer::DataV() const { |
208 return v_plane_; | 272 return v_plane_; |
209 default: | |
210 RTC_NOTREACHED(); | |
211 return nullptr; | |
212 } | |
213 } | 273 } |
214 | 274 |
215 int WrappedI420Buffer::stride(PlaneType type) const { | 275 int WrappedI420Buffer::StrideY() const { |
216 switch (type) { | 276 return y_stride_; |
217 case kYPlane: | 277 } |
218 return y_stride_; | 278 int WrappedI420Buffer::StrideU() const { |
219 case kUPlane: | 279 return u_stride_; |
220 return u_stride_; | 280 } |
221 case kVPlane: | 281 int WrappedI420Buffer::StrideV() const { |
222 return v_stride_; | 282 return v_stride_; |
223 default: | |
224 RTC_NOTREACHED(); | |
225 return 0; | |
226 } | |
227 } | 283 } |
228 | 284 |
229 void* WrappedI420Buffer::native_handle() const { | 285 void* WrappedI420Buffer::native_handle() const { |
230 return nullptr; | 286 return nullptr; |
231 } | 287 } |
232 | 288 |
233 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { | 289 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { |
234 RTC_NOTREACHED(); | 290 RTC_NOTREACHED(); |
235 return nullptr; | 291 return nullptr; |
236 } | 292 } |
237 | 293 |
238 rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( | 294 rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( |
239 const rtc::scoped_refptr<VideoFrameBuffer>& buffer, | 295 const rtc::scoped_refptr<VideoFrameBuffer>& buffer, |
240 int cropped_width, | 296 int cropped_width, |
241 int cropped_height) { | 297 int cropped_height) { |
242 RTC_CHECK(buffer->native_handle() == nullptr); | 298 RTC_CHECK(buffer->native_handle() == nullptr); |
243 RTC_CHECK_LE(cropped_width, buffer->width()); | 299 RTC_CHECK_LE(cropped_width, buffer->width()); |
244 RTC_CHECK_LE(cropped_height, buffer->height()); | 300 RTC_CHECK_LE(cropped_height, buffer->height()); |
245 if (buffer->width() == cropped_width && buffer->height() == cropped_height) | 301 if (buffer->width() == cropped_width && buffer->height() == cropped_height) |
246 return buffer; | 302 return buffer; |
247 | 303 |
248 // Center crop to |cropped_width| x |cropped_height|. | 304 // Center crop to |cropped_width| x |cropped_height|. |
249 // Make sure offset is even so that u/v plane becomes aligned. | 305 // Make sure offset is even so that u/v plane becomes aligned. |
250 const int uv_offset_x = (buffer->width() - cropped_width) / 4; | 306 const int uv_offset_x = (buffer->width() - cropped_width) / 4; |
251 const int uv_offset_y = (buffer->height() - cropped_height) / 4; | 307 const int uv_offset_y = (buffer->height() - cropped_height) / 4; |
252 const int offset_x = uv_offset_x * 2; | 308 const int offset_x = uv_offset_x * 2; |
253 const int offset_y = uv_offset_y * 2; | 309 const int offset_y = uv_offset_y * 2; |
254 | 310 |
255 const uint8_t* y_plane = buffer->data(kYPlane) + | 311 const uint8_t* y_plane = buffer->DataY() + |
256 buffer->stride(kYPlane) * offset_y + offset_x; | 312 buffer->StrideY() * offset_y + offset_x; |
257 const uint8_t* u_plane = buffer->data(kUPlane) + | 313 const uint8_t* u_plane = buffer->DataU() + |
258 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x; | 314 buffer->StrideU() * uv_offset_y + uv_offset_x; |
259 const uint8_t* v_plane = buffer->data(kVPlane) + | 315 const uint8_t* v_plane = buffer->DataV() + |
260 buffer->stride(kVPlane) * uv_offset_y + uv_offset_x; | 316 buffer->StrideV() * uv_offset_y + uv_offset_x; |
261 return new rtc::RefCountedObject<WrappedI420Buffer>( | 317 return new rtc::RefCountedObject<WrappedI420Buffer>( |
262 cropped_width, cropped_height, | 318 cropped_width, cropped_height, |
263 y_plane, buffer->stride(kYPlane), | 319 y_plane, buffer->StrideY(), |
264 u_plane, buffer->stride(kUPlane), | 320 u_plane, buffer->StrideU(), |
265 v_plane, buffer->stride(kVPlane), | 321 v_plane, buffer->StrideV(), |
266 rtc::KeepRefUntilDone(buffer)); | 322 rtc::KeepRefUntilDone(buffer)); |
267 } | 323 } |
268 | 324 |
269 } // namespace webrtc | 325 } // namespace webrtc |
OLD | NEW |