| 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 |