| 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 #include "webrtc/common_video/include/video_frame_buffer.h" | 10 #include "webrtc/api/video/i420_buffer.h" |
| 11 | 11 |
| 12 #include <string.h> | 12 #include <string.h> |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 #include <utility> |
| 15 | 16 |
| 16 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
| 17 #include "webrtc/base/keep_ref_until_done.h" | 18 #include "webrtc/base/keep_ref_until_done.h" |
| 18 #include "libyuv/convert.h" | 19 #include "libyuv/convert.h" |
| 19 #include "libyuv/planar_functions.h" | 20 #include "libyuv/planar_functions.h" |
| 20 #include "libyuv/scale.h" | 21 #include "libyuv/scale.h" |
| 21 | 22 |
| 22 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. | 23 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. |
| 23 static const int kBufferAlignment = 64; | 24 static const int kBufferAlignment = 64; |
| 24 | 25 |
| 25 namespace webrtc { | 26 namespace webrtc { |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 int I420DataSize(int height, int stride_y, int stride_u, int stride_v) { | 30 int I420DataSize(int height, int stride_y, int stride_u, int stride_v) { |
| 30 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2); | 31 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2); |
| 31 } | 32 } |
| 32 | 33 |
| 33 } // namespace | 34 } // namespace |
| 34 | 35 |
| 35 VideoFrameBuffer::~VideoFrameBuffer() {} | |
| 36 | |
| 37 I420Buffer::I420Buffer(int width, int height) | 36 I420Buffer::I420Buffer(int width, int height) |
| 38 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { | 37 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { |
| 39 } | 38 } |
| 40 | 39 |
| 41 I420Buffer::I420Buffer(int width, | 40 I420Buffer::I420Buffer(int width, |
| 42 int height, | 41 int height, |
| 43 int stride_y, | 42 int stride_y, |
| 44 int stride_u, | 43 int stride_u, |
| 45 int stride_v) | 44 int stride_v) |
| 46 : width_(width), | 45 : width_(width), |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 data_u, stride_u, | 96 data_u, stride_u, |
| 98 data_v, stride_v, | 97 data_v, stride_v, |
| 99 buffer->MutableDataY(), buffer->StrideY(), | 98 buffer->MutableDataY(), buffer->StrideY(), |
| 100 buffer->MutableDataU(), buffer->StrideU(), | 99 buffer->MutableDataU(), buffer->StrideU(), |
| 101 buffer->MutableDataV(), buffer->StrideV(), | 100 buffer->MutableDataV(), buffer->StrideV(), |
| 102 width, height)); | 101 width, height)); |
| 103 return buffer; | 102 return buffer; |
| 104 } | 103 } |
| 105 | 104 |
| 106 // static | 105 // static |
| 107 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::Rotate( | 106 rtc::scoped_refptr<I420Buffer> I420Buffer::Rotate( |
| 108 rtc::scoped_refptr<VideoFrameBuffer> src, | 107 const VideoFrameBuffer& src, VideoRotation rotation) { |
| 109 VideoRotation rotation) { | 108 RTC_CHECK(src.DataY()); |
| 110 RTC_CHECK(src->DataY()); | 109 RTC_CHECK(src.DataU()); |
| 111 RTC_CHECK(src->DataU()); | 110 RTC_CHECK(src.DataV()); |
| 112 RTC_CHECK(src->DataV()); | |
| 113 | 111 |
| 114 if (rotation == webrtc::kVideoRotation_0) { | 112 int rotated_width = src.width(); |
| 115 return src; | 113 int rotated_height = src.height(); |
| 116 } | |
| 117 | |
| 118 int rotated_width = src->width(); | |
| 119 int rotated_height = src->height(); | |
| 120 if (rotation == webrtc::kVideoRotation_90 || | 114 if (rotation == webrtc::kVideoRotation_90 || |
| 121 rotation == webrtc::kVideoRotation_270) { | 115 rotation == webrtc::kVideoRotation_270) { |
| 122 std::swap(rotated_width, rotated_height); | 116 std::swap(rotated_width, rotated_height); |
| 123 } | 117 } |
| 124 | 118 |
| 125 rtc::scoped_refptr<webrtc::I420Buffer> buffer = | 119 rtc::scoped_refptr<webrtc::I420Buffer> buffer = |
| 126 I420Buffer::Create(rotated_width, rotated_height); | 120 I420Buffer::Create(rotated_width, rotated_height); |
| 127 | 121 |
| 128 RTC_CHECK_EQ(0, libyuv::I420Rotate( | 122 RTC_CHECK_EQ(0, libyuv::I420Rotate( |
| 129 src->DataY(), src->StrideY(), | 123 src.DataY(), src.StrideY(), |
| 130 src->DataU(), src->StrideU(), | 124 src.DataU(), src.StrideU(), |
| 131 src->DataV(), src->StrideV(), | 125 src.DataV(), src.StrideV(), |
| 132 buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(), | 126 buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(), |
| 133 buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), | 127 buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), |
| 134 src->width(), src->height(), | 128 src.width(), src.height(), |
| 135 static_cast<libyuv::RotationMode>(rotation))); | 129 static_cast<libyuv::RotationMode>(rotation))); |
| 136 | 130 |
| 137 return buffer; | 131 return buffer; |
| 138 } | 132 } |
| 139 | 133 |
| 134 // static |
| 135 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::Rotate( |
| 136 rtc::scoped_refptr<VideoFrameBuffer> src, |
| 137 VideoRotation rotation) { |
| 138 if (rotation == webrtc::kVideoRotation_0) { |
| 139 return src; |
| 140 } else { |
| 141 return Rotate(*src, rotation); |
| 142 } |
| 143 } |
| 144 |
| 140 void I420Buffer::InitializeData() { | 145 void I420Buffer::InitializeData() { |
| 141 memset(data_.get(), 0, | 146 memset(data_.get(), 0, |
| 142 I420DataSize(height_, stride_y_, stride_u_, stride_v_)); | 147 I420DataSize(height_, stride_y_, stride_u_, stride_v_)); |
| 143 } | 148 } |
| 144 | 149 |
| 145 int I420Buffer::width() const { | 150 int I420Buffer::width() const { |
| 146 return width_; | 151 return width_; |
| 147 } | 152 } |
| 148 | 153 |
| 149 int I420Buffer::height() const { | 154 int I420Buffer::height() const { |
| 150 return height_; | 155 return height_; |
| 151 } | 156 } |
| 152 | 157 |
| 153 const uint8_t* I420Buffer::DataY() const { | 158 const uint8_t* I420Buffer::DataY() const { |
| 154 return data_.get(); | 159 return data_.get(); |
| 155 } | 160 } |
| 156 const uint8_t* I420Buffer::DataU() const { | 161 const uint8_t* I420Buffer::DataU() const { |
| 157 return data_.get() + stride_y_ * height_; | 162 return data_.get() + stride_y_ * height_; |
| 158 } | 163 } |
| 159 const uint8_t* I420Buffer::DataV() const { | 164 const uint8_t* I420Buffer::DataV() const { |
| 160 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2); | 165 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2); |
| 161 } | 166 } |
| 162 | 167 |
| 163 uint8_t* I420Buffer::MutableDataY() { | |
| 164 return const_cast<uint8_t*>(DataY()); | |
| 165 } | |
| 166 uint8_t* I420Buffer::MutableDataU() { | |
| 167 return const_cast<uint8_t*>(DataU()); | |
| 168 } | |
| 169 uint8_t* I420Buffer::MutableDataV() { | |
| 170 return const_cast<uint8_t*>(DataV()); | |
| 171 } | |
| 172 | |
| 173 int I420Buffer::StrideY() const { | 168 int I420Buffer::StrideY() const { |
| 174 return stride_y_; | 169 return stride_y_; |
| 175 } | 170 } |
| 176 int I420Buffer::StrideU() const { | 171 int I420Buffer::StrideU() const { |
| 177 return stride_u_; | 172 return stride_u_; |
| 178 } | 173 } |
| 179 int I420Buffer::StrideV() const { | 174 int I420Buffer::StrideV() const { |
| 180 return stride_v_; | 175 return stride_v_; |
| 181 } | 176 } |
| 182 | 177 |
| 183 void* I420Buffer::native_handle() const { | 178 void* I420Buffer::native_handle() const { |
| 184 return nullptr; | 179 return nullptr; |
| 185 } | 180 } |
| 186 | 181 |
| 187 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { | 182 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { |
| 188 RTC_NOTREACHED(); | 183 RTC_NOTREACHED(); |
| 189 return nullptr; | 184 return nullptr; |
| 190 } | 185 } |
| 191 | 186 |
| 192 void I420Buffer::SetToBlack() { | 187 uint8_t* I420Buffer::MutableDataY() { |
| 193 RTC_CHECK(libyuv::I420Rect(MutableDataY(), StrideY(), | 188 return const_cast<uint8_t*>(DataY()); |
| 194 MutableDataU(), StrideU(), | 189 } |
| 195 MutableDataV(), StrideV(), | 190 uint8_t* I420Buffer::MutableDataU() { |
| 196 0, 0, width(), height(), | 191 return const_cast<uint8_t*>(DataU()); |
| 192 } |
| 193 uint8_t* I420Buffer::MutableDataV() { |
| 194 return const_cast<uint8_t*>(DataV()); |
| 195 } |
| 196 |
| 197 // static |
| 198 void I420Buffer::SetBlack(I420Buffer* buffer) { |
| 199 RTC_CHECK(libyuv::I420Rect(buffer->MutableDataY(), buffer->StrideY(), |
| 200 buffer->MutableDataU(), buffer->StrideU(), |
| 201 buffer->MutableDataV(), buffer->StrideV(), |
| 202 0, 0, buffer->width(), buffer->height(), |
| 197 0, 128, 128) == 0); | 203 0, 128, 128) == 0); |
| 198 } | 204 } |
| 199 | 205 |
| 200 void I420Buffer::CropAndScaleFrom( | 206 void I420Buffer::CropAndScaleFrom( |
| 201 const VideoFrameBuffer& src, | 207 const VideoFrameBuffer& src, |
| 202 int offset_x, | 208 int offset_x, |
| 203 int offset_y, | 209 int offset_y, |
| 204 int crop_width, | 210 int crop_width, |
| 205 int crop_height) { | 211 int crop_height) { |
| 206 RTC_CHECK_LE(crop_width, src.width()); | 212 RTC_CHECK_LE(crop_width, src.width()); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 CropAndScaleFrom( | 250 CropAndScaleFrom( |
| 245 src, | 251 src, |
| 246 (src.width() - crop_width) / 2, (src.height() - crop_height) / 2, | 252 (src.width() - crop_width) / 2, (src.height() - crop_height) / 2, |
| 247 crop_width, crop_height); | 253 crop_width, crop_height); |
| 248 } | 254 } |
| 249 | 255 |
| 250 void I420Buffer::ScaleFrom(const VideoFrameBuffer& src) { | 256 void I420Buffer::ScaleFrom(const VideoFrameBuffer& src) { |
| 251 CropAndScaleFrom(src, 0, 0, src.width(), src.height()); | 257 CropAndScaleFrom(src, 0, 0, src.width(), src.height()); |
| 252 } | 258 } |
| 253 | 259 |
| 254 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, | |
| 255 int width, | |
| 256 int height) | |
| 257 : native_handle_(native_handle), width_(width), height_(height) { | |
| 258 RTC_DCHECK(native_handle != nullptr); | |
| 259 RTC_DCHECK_GT(width, 0); | |
| 260 RTC_DCHECK_GT(height, 0); | |
| 261 } | |
| 262 | |
| 263 int NativeHandleBuffer::width() const { | |
| 264 return width_; | |
| 265 } | |
| 266 | |
| 267 int NativeHandleBuffer::height() const { | |
| 268 return height_; | |
| 269 } | |
| 270 | |
| 271 const uint8_t* NativeHandleBuffer::DataY() const { | |
| 272 RTC_NOTREACHED(); // Should not be called. | |
| 273 return nullptr; | |
| 274 } | |
| 275 const uint8_t* NativeHandleBuffer::DataU() const { | |
| 276 RTC_NOTREACHED(); // Should not be called. | |
| 277 return nullptr; | |
| 278 } | |
| 279 const uint8_t* NativeHandleBuffer::DataV() const { | |
| 280 RTC_NOTREACHED(); // Should not be called. | |
| 281 return nullptr; | |
| 282 } | |
| 283 | |
| 284 int NativeHandleBuffer::StrideY() const { | |
| 285 RTC_NOTREACHED(); // Should not be called. | |
| 286 return 0; | |
| 287 } | |
| 288 int NativeHandleBuffer::StrideU() const { | |
| 289 RTC_NOTREACHED(); // Should not be called. | |
| 290 return 0; | |
| 291 } | |
| 292 int NativeHandleBuffer::StrideV() const { | |
| 293 RTC_NOTREACHED(); // Should not be called. | |
| 294 return 0; | |
| 295 } | |
| 296 | |
| 297 void* NativeHandleBuffer::native_handle() const { | |
| 298 return native_handle_; | |
| 299 } | |
| 300 | |
| 301 WrappedI420Buffer::WrappedI420Buffer(int width, | |
| 302 int height, | |
| 303 const uint8_t* y_plane, | |
| 304 int y_stride, | |
| 305 const uint8_t* u_plane, | |
| 306 int u_stride, | |
| 307 const uint8_t* v_plane, | |
| 308 int v_stride, | |
| 309 const rtc::Callback0<void>& no_longer_used) | |
| 310 : width_(width), | |
| 311 height_(height), | |
| 312 y_plane_(y_plane), | |
| 313 u_plane_(u_plane), | |
| 314 v_plane_(v_plane), | |
| 315 y_stride_(y_stride), | |
| 316 u_stride_(u_stride), | |
| 317 v_stride_(v_stride), | |
| 318 no_longer_used_cb_(no_longer_used) { | |
| 319 } | |
| 320 | |
| 321 WrappedI420Buffer::~WrappedI420Buffer() { | |
| 322 no_longer_used_cb_(); | |
| 323 } | |
| 324 | |
| 325 int WrappedI420Buffer::width() const { | |
| 326 return width_; | |
| 327 } | |
| 328 | |
| 329 int WrappedI420Buffer::height() const { | |
| 330 return height_; | |
| 331 } | |
| 332 | |
| 333 const uint8_t* WrappedI420Buffer::DataY() const { | |
| 334 return y_plane_; | |
| 335 } | |
| 336 const uint8_t* WrappedI420Buffer::DataU() const { | |
| 337 return u_plane_; | |
| 338 } | |
| 339 const uint8_t* WrappedI420Buffer::DataV() const { | |
| 340 return v_plane_; | |
| 341 } | |
| 342 | |
| 343 int WrappedI420Buffer::StrideY() const { | |
| 344 return y_stride_; | |
| 345 } | |
| 346 int WrappedI420Buffer::StrideU() const { | |
| 347 return u_stride_; | |
| 348 } | |
| 349 int WrappedI420Buffer::StrideV() const { | |
| 350 return v_stride_; | |
| 351 } | |
| 352 | |
| 353 void* WrappedI420Buffer::native_handle() const { | |
| 354 return nullptr; | |
| 355 } | |
| 356 | |
| 357 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { | |
| 358 RTC_NOTREACHED(); | |
| 359 return nullptr; | |
| 360 } | |
| 361 | |
| 362 } // namespace webrtc | 260 } // namespace webrtc |
| OLD | NEW |