1/* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/common_video/include/video_frame_buffer.h" 12 13#include "webrtc/base/checks.h" 14#include "webrtc/base/keep_ref_until_done.h" 15 16// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. 17static const int kBufferAlignment = 64; 18 19namespace webrtc { 20 21uint8_t* VideoFrameBuffer::MutableData(PlaneType type) { 22 RTC_NOTREACHED(); 23 return nullptr; 24} 25 26VideoFrameBuffer::~VideoFrameBuffer() {} 27 28I420Buffer::I420Buffer(int width, int height) 29 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { 30} 31 32I420Buffer::I420Buffer(int width, 33 int height, 34 int stride_y, 35 int stride_u, 36 int stride_v) 37 : width_(width), 38 height_(height), 39 stride_y_(stride_y), 40 stride_u_(stride_u), 41 stride_v_(stride_v), 42 data_(static_cast<uint8_t*>(AlignedMalloc( 43 stride_y * height + (stride_u + stride_v) * ((height + 1) / 2), 44 kBufferAlignment))) { 45 RTC_DCHECK_GT(width, 0); 46 RTC_DCHECK_GT(height, 0); 47 RTC_DCHECK_GE(stride_y, width); 48 RTC_DCHECK_GE(stride_u, (width + 1) / 2); 49 RTC_DCHECK_GE(stride_v, (width + 1) / 2); 50} 51 52I420Buffer::~I420Buffer() { 53} 54 55int I420Buffer::width() const { 56 return width_; 57} 58 59int I420Buffer::height() const { 60 return height_; 61} 62 63const uint8_t* I420Buffer::data(PlaneType type) const { 64 switch (type) { 65 case kYPlane: 66 return data_.get(); 67 case kUPlane: 68 return data_.get() + stride_y_ * height_; 69 case kVPlane: 70 return data_.get() + stride_y_ * height_ + 71 stride_u_ * ((height_ + 1) / 2); 72 default: 73 RTC_NOTREACHED(); 74 return nullptr; 75 } 76} 77 78uint8_t* I420Buffer::MutableData(PlaneType type) { 79 RTC_DCHECK(HasOneRef()); 80 return const_cast<uint8_t*>( 81 static_cast<const VideoFrameBuffer*>(this)->data(type)); 82} 83 84int I420Buffer::stride(PlaneType type) const { 85 switch (type) { 86 case kYPlane: 87 return stride_y_; 88 case kUPlane: 89 return stride_u_; 90 case kVPlane: 91 return stride_v_; 92 default: 93 RTC_NOTREACHED(); 94 return 0; 95 } 96} 97 98void* I420Buffer::native_handle() const { 99 return nullptr; 100} 101 102rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() { 103 RTC_NOTREACHED(); 104 return nullptr; 105} 106 107NativeHandleBuffer::NativeHandleBuffer(void* native_handle, 108 int width, 109 int height) 110 : native_handle_(native_handle), width_(width), height_(height) { 111 RTC_DCHECK(native_handle != nullptr); 112 RTC_DCHECK_GT(width, 0); 113 RTC_DCHECK_GT(height, 0); 114} 115 116int NativeHandleBuffer::width() const { 117 return width_; 118} 119 120int NativeHandleBuffer::height() const { 121 return height_; 122} 123 124const uint8_t* NativeHandleBuffer::data(PlaneType type) const { 125 RTC_NOTREACHED(); // Should not be called. 126 return nullptr; 127} 128 129int NativeHandleBuffer::stride(PlaneType type) const { 130 RTC_NOTREACHED(); // Should not be called. 131 return 0; 132} 133 134void* NativeHandleBuffer::native_handle() const { 135 return native_handle_; 136} 137 138WrappedI420Buffer::WrappedI420Buffer(int width, 139 int height, 140 const uint8_t* y_plane, 141 int y_stride, 142 const uint8_t* u_plane, 143 int u_stride, 144 const uint8_t* v_plane, 145 int v_stride, 146 const rtc::Callback0<void>& no_longer_used) 147 : width_(width), 148 height_(height), 149 y_plane_(y_plane), 150 u_plane_(u_plane), 151 v_plane_(v_plane), 152 y_stride_(y_stride), 153 u_stride_(u_stride), 154 v_stride_(v_stride), 155 no_longer_used_cb_(no_longer_used) { 156} 157 158WrappedI420Buffer::~WrappedI420Buffer() { 159 no_longer_used_cb_(); 160} 161 162int WrappedI420Buffer::width() const { 163 return width_; 164} 165 166int WrappedI420Buffer::height() const { 167 return height_; 168} 169 170const uint8_t* WrappedI420Buffer::data(PlaneType type) const { 171 switch (type) { 172 case kYPlane: 173 return y_plane_; 174 case kUPlane: 175 return u_plane_; 176 case kVPlane: 177 return v_plane_; 178 default: 179 RTC_NOTREACHED(); 180 return nullptr; 181 } 182} 183 184int WrappedI420Buffer::stride(PlaneType type) const { 185 switch (type) { 186 case kYPlane: 187 return y_stride_; 188 case kUPlane: 189 return u_stride_; 190 case kVPlane: 191 return v_stride_; 192 default: 193 RTC_NOTREACHED(); 194 return 0; 195 } 196} 197 198void* WrappedI420Buffer::native_handle() const { 199 return nullptr; 200} 201 202rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() { 203 RTC_NOTREACHED(); 204 return nullptr; 205} 206 207rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop( 208 const rtc::scoped_refptr<VideoFrameBuffer>& buffer, 209 int cropped_width, 210 int cropped_height) { 211 RTC_CHECK(buffer->native_handle() == nullptr); 212 RTC_CHECK_LE(cropped_width, buffer->width()); 213 RTC_CHECK_LE(cropped_height, buffer->height()); 214 if (buffer->width() == cropped_width && buffer->height() == cropped_height) 215 return buffer; 216 217 // Center crop to |cropped_width| x |cropped_height|. 218 // Make sure offset is even so that u/v plane becomes aligned. 219 const int uv_offset_x = (buffer->width() - cropped_width) / 4; 220 const int uv_offset_y = (buffer->height() - cropped_height) / 4; 221 const int offset_x = uv_offset_x * 2; 222 const int offset_y = uv_offset_y * 2; 223 224 const uint8_t* y_plane = buffer->data(kYPlane) + 225 buffer->stride(kYPlane) * offset_y + offset_x; 226 const uint8_t* u_plane = buffer->data(kUPlane) + 227 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x; 228 const uint8_t* v_plane = buffer->data(kVPlane) + 229 buffer->stride(kVPlane) * uv_offset_y + uv_offset_x; 230 return new rtc::RefCountedObject<WrappedI420Buffer>( 231 cropped_width, cropped_height, 232 y_plane, buffer->stride(kYPlane), 233 u_plane, buffer->stride(kUPlane), 234 v_plane, buffer->stride(kVPlane), 235 rtc::KeepRefUntilDone(buffer)); 236} 237 238} // namespace webrtc 239