| 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/common_video/include/video_frame_buffer.h" |
| 11 | 11 |
| 12 #include <string.h> | 12 #include <string.h> |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 | 15 |
| 16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
| 17 #include "webrtc/base/keep_ref_until_done.h" | 17 #include "webrtc/base/keep_ref_until_done.h" |
| 18 #include "libyuv/convert.h" | 18 #include "libyuv/convert.h" |
| 19 #include "libyuv/planar_functions.h" | 19 #include "libyuv/planar_functions.h" |
| 20 #include "libyuv/scale.h" | 20 #include "libyuv/scale.h" |
| 21 | 21 |
| 22 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. | |
| 23 static const int kBufferAlignment = 64; | |
| 24 | |
| 25 namespace webrtc { | 22 namespace webrtc { |
| 26 | 23 |
| 27 namespace { | |
| 28 | |
| 29 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 } | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 VideoFrameBuffer::~VideoFrameBuffer() {} | |
| 36 | |
| 37 I420Buffer::I420Buffer(int width, int height) | |
| 38 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { | |
| 39 } | |
| 40 | |
| 41 I420Buffer::I420Buffer(int width, | |
| 42 int height, | |
| 43 int stride_y, | |
| 44 int stride_u, | |
| 45 int stride_v) | |
| 46 : width_(width), | |
| 47 height_(height), | |
| 48 stride_y_(stride_y), | |
| 49 stride_u_(stride_u), | |
| 50 stride_v_(stride_v), | |
| 51 data_(static_cast<uint8_t*>(AlignedMalloc( | |
| 52 I420DataSize(height, stride_y, stride_u, stride_v), | |
| 53 kBufferAlignment))) { | |
| 54 RTC_DCHECK_GT(width, 0); | |
| 55 RTC_DCHECK_GT(height, 0); | |
| 56 RTC_DCHECK_GE(stride_y, width); | |
| 57 RTC_DCHECK_GE(stride_u, (width + 1) / 2); | |
| 58 RTC_DCHECK_GE(stride_v, (width + 1) / 2); | |
| 59 } | |
| 60 | |
| 61 I420Buffer::~I420Buffer() { | |
| 62 } | |
| 63 | |
| 64 // static | |
| 65 rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, int height) { | |
| 66 return new rtc::RefCountedObject<I420Buffer>(width, height); | |
| 67 } | |
| 68 | |
| 69 // static | |
| 70 rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, | |
| 71 int height, | |
| 72 int stride_y, | |
| 73 int stride_u, | |
| 74 int stride_v) { | |
| 75 return new rtc::RefCountedObject<I420Buffer>( | |
| 76 width, height, stride_y, stride_u, stride_v); | |
| 77 } | |
| 78 | |
| 79 // static | |
| 80 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( | |
| 81 const VideoFrameBuffer& source) { | |
| 82 return Copy(source.width(), source.height(), | |
| 83 source.DataY(), source.StrideY(), | |
| 84 source.DataU(), source.StrideU(), | |
| 85 source.DataV(), source.StrideV()); | |
| 86 } | |
| 87 | |
| 88 // static | |
| 89 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( | |
| 90 int width, int height, | |
| 91 const uint8_t* data_y, int stride_y, | |
| 92 const uint8_t* data_u, int stride_u, | |
| 93 const uint8_t* data_v, int stride_v) { | |
| 94 // Note: May use different strides than the input data. | |
| 95 rtc::scoped_refptr<I420Buffer> buffer = Create(width, height); | |
| 96 RTC_CHECK_EQ(0, libyuv::I420Copy(data_y, stride_y, | |
| 97 data_u, stride_u, | |
| 98 data_v, stride_v, | |
| 99 buffer->MutableDataY(), buffer->StrideY(), | |
| 100 buffer->MutableDataU(), buffer->StrideU(), | |
| 101 buffer->MutableDataV(), buffer->StrideV(), | |
| 102 width, height)); | |
| 103 return buffer; | |
| 104 } | |
| 105 | |
| 106 // static | |
| 107 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::Rotate( | |
| 108 rtc::scoped_refptr<VideoFrameBuffer> src, | |
| 109 VideoRotation rotation) { | |
| 110 RTC_CHECK(src->DataY()); | |
| 111 RTC_CHECK(src->DataU()); | |
| 112 RTC_CHECK(src->DataV()); | |
| 113 | |
| 114 if (rotation == webrtc::kVideoRotation_0) { | |
| 115 return src; | |
| 116 } | |
| 117 | |
| 118 int rotated_width = src->width(); | |
| 119 int rotated_height = src->height(); | |
| 120 if (rotation == webrtc::kVideoRotation_90 || | |
| 121 rotation == webrtc::kVideoRotation_270) { | |
| 122 std::swap(rotated_width, rotated_height); | |
| 123 } | |
| 124 | |
| 125 rtc::scoped_refptr<webrtc::I420Buffer> buffer = | |
| 126 I420Buffer::Create(rotated_width, rotated_height); | |
| 127 | |
| 128 RTC_CHECK_EQ(0, libyuv::I420Rotate( | |
| 129 src->DataY(), src->StrideY(), | |
| 130 src->DataU(), src->StrideU(), | |
| 131 src->DataV(), src->StrideV(), | |
| 132 buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(), | |
| 133 buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), | |
| 134 src->width(), src->height(), | |
| 135 static_cast<libyuv::RotationMode>(rotation))); | |
| 136 | |
| 137 return buffer; | |
| 138 } | |
| 139 | |
| 140 void I420Buffer::InitializeData() { | |
| 141 memset(data_.get(), 0, | |
| 142 I420DataSize(height_, stride_y_, stride_u_, stride_v_)); | |
| 143 } | |
| 144 | |
| 145 int I420Buffer::width() const { | |
| 146 return width_; | |
| 147 } | |
| 148 | |
| 149 int I420Buffer::height() const { | |
| 150 return height_; | |
| 151 } | |
| 152 | |
| 153 const uint8_t* I420Buffer::DataY() const { | |
| 154 return data_.get(); | |
| 155 } | |
| 156 const uint8_t* I420Buffer::DataU() const { | |
| 157 return data_.get() + stride_y_ * height_; | |
| 158 } | |
| 159 const uint8_t* I420Buffer::DataV() const { | |
| 160 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2); | |
| 161 } | |
| 162 | |
| 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 { | |
| 174 return stride_y_; | |
| 175 } | |
| 176 int I420Buffer::StrideU() const { | |
| 177 return stride_u_; | |
| 178 } | |
| 179 int I420Buffer::StrideV() const { | |
| 180 return stride_v_; | |
| 181 } | |
| 182 | |
| 183 void* I420Buffer::native_handle() const { | |
| 184 return nullptr; | |
| 185 } | |
| 186 | |
| 187 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { | |
| 188 RTC_NOTREACHED(); | |
| 189 return nullptr; | |
| 190 } | |
| 191 | |
| 192 void I420Buffer::SetToBlack() { | |
| 193 RTC_CHECK(libyuv::I420Rect(MutableDataY(), StrideY(), | |
| 194 MutableDataU(), StrideU(), | |
| 195 MutableDataV(), StrideV(), | |
| 196 0, 0, width(), height(), | |
| 197 0, 128, 128) == 0); | |
| 198 } | |
| 199 | |
| 200 void I420Buffer::CropAndScaleFrom( | |
| 201 const VideoFrameBuffer& src, | |
| 202 int offset_x, | |
| 203 int offset_y, | |
| 204 int crop_width, | |
| 205 int crop_height) { | |
| 206 RTC_CHECK_LE(crop_width, src.width()); | |
| 207 RTC_CHECK_LE(crop_height, src.height()); | |
| 208 RTC_CHECK_LE(crop_width + offset_x, src.width()); | |
| 209 RTC_CHECK_LE(crop_height + offset_y, src.height()); | |
| 210 RTC_CHECK_GE(offset_x, 0); | |
| 211 RTC_CHECK_GE(offset_y, 0); | |
| 212 | |
| 213 // Make sure offset is even so that u/v plane becomes aligned. | |
| 214 const int uv_offset_x = offset_x / 2; | |
| 215 const int uv_offset_y = offset_y / 2; | |
| 216 offset_x = uv_offset_x * 2; | |
| 217 offset_y = uv_offset_y * 2; | |
| 218 | |
| 219 const uint8_t* y_plane = | |
| 220 src.DataY() + src.StrideY() * offset_y + offset_x; | |
| 221 const uint8_t* u_plane = | |
| 222 src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x; | |
| 223 const uint8_t* v_plane = | |
| 224 src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x; | |
| 225 int res = libyuv::I420Scale(y_plane, src.StrideY(), | |
| 226 u_plane, src.StrideU(), | |
| 227 v_plane, src.StrideV(), | |
| 228 crop_width, crop_height, | |
| 229 MutableDataY(), StrideY(), | |
| 230 MutableDataU(), StrideU(), | |
| 231 MutableDataV(), StrideV(), | |
| 232 width(), height(), libyuv::kFilterBox); | |
| 233 | |
| 234 RTC_DCHECK_EQ(res, 0); | |
| 235 } | |
| 236 | |
| 237 void I420Buffer::CropAndScaleFrom( | |
| 238 const VideoFrameBuffer& src) { | |
| 239 const int crop_width = | |
| 240 std::min(src.width(), width() * src.height() / height()); | |
| 241 const int crop_height = | |
| 242 std::min(src.height(), height() * src.width() / width()); | |
| 243 | |
| 244 CropAndScaleFrom( | |
| 245 src, | |
| 246 (src.width() - crop_width) / 2, (src.height() - crop_height) / 2, | |
| 247 crop_width, crop_height); | |
| 248 } | |
| 249 | |
| 250 void I420Buffer::ScaleFrom(const VideoFrameBuffer& src) { | |
| 251 CropAndScaleFrom(src, 0, 0, src.width(), src.height()); | |
| 252 } | |
| 253 | |
| 254 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, | 24 NativeHandleBuffer::NativeHandleBuffer(void* native_handle, |
| 255 int width, | 25 int width, |
| 256 int height) | 26 int height) |
| 257 : native_handle_(native_handle), width_(width), height_(height) { | 27 : native_handle_(native_handle), width_(width), height_(height) { |
| 258 RTC_DCHECK(native_handle != nullptr); | 28 RTC_DCHECK(native_handle != nullptr); |
| 259 RTC_DCHECK_GT(width, 0); | 29 RTC_DCHECK_GT(width, 0); |
| 260 RTC_DCHECK_GT(height, 0); | 30 RTC_DCHECK_GT(height, 0); |
| 261 } | 31 } |
| 262 | 32 |
| 263 int NativeHandleBuffer::width() const { | 33 int NativeHandleBuffer::width() const { |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 void* WrappedI420Buffer::native_handle() const { | 123 void* WrappedI420Buffer::native_handle() const { |
| 354 return nullptr; | 124 return nullptr; |
| 355 } | 125 } |
| 356 | 126 |
| 357 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { | 127 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { |
| 358 RTC_NOTREACHED(); | 128 RTC_NOTREACHED(); |
| 359 return nullptr; | 129 return nullptr; |
| 360 } | 130 } |
| 361 | 131 |
| 362 } // namespace webrtc | 132 } // namespace webrtc |
| OLD | NEW |