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.
17 static const int kBufferAlignment = 64;
18 
19 namespace webrtc {
20 
MutableData(PlaneType type)21 uint8_t* VideoFrameBuffer::MutableData(PlaneType type) {
22   RTC_NOTREACHED();
23   return nullptr;
24 }
25 
~VideoFrameBuffer()26 VideoFrameBuffer::~VideoFrameBuffer() {}
27 
I420Buffer(int width,int height)28 I420Buffer::I420Buffer(int width, int height)
29     : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
30 }
31 
I420Buffer(int width,int height,int stride_y,int stride_u,int stride_v)32 I420Buffer::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 
~I420Buffer()52 I420Buffer::~I420Buffer() {
53 }
54 
width() const55 int I420Buffer::width() const {
56   return width_;
57 }
58 
height() const59 int I420Buffer::height() const {
60   return height_;
61 }
62 
data(PlaneType type) const63 const 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 
MutableData(PlaneType type)78 uint8_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 
stride(PlaneType type) const84 int 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 
native_handle() const98 void* I420Buffer::native_handle() const {
99   return nullptr;
100 }
101 
NativeToI420Buffer()102 rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
103   RTC_NOTREACHED();
104   return nullptr;
105 }
106 
NativeHandleBuffer(void * native_handle,int width,int height)107 NativeHandleBuffer::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 
width() const116 int NativeHandleBuffer::width() const {
117   return width_;
118 }
119 
height() const120 int NativeHandleBuffer::height() const {
121   return height_;
122 }
123 
data(PlaneType type) const124 const uint8_t* NativeHandleBuffer::data(PlaneType type) const {
125   RTC_NOTREACHED();  // Should not be called.
126   return nullptr;
127 }
128 
stride(PlaneType type) const129 int NativeHandleBuffer::stride(PlaneType type) const {
130   RTC_NOTREACHED();  // Should not be called.
131   return 0;
132 }
133 
native_handle() const134 void* NativeHandleBuffer::native_handle() const {
135   return native_handle_;
136 }
137 
WrappedI420Buffer(int width,int height,const uint8_t * y_plane,int y_stride,const uint8_t * u_plane,int u_stride,const uint8_t * v_plane,int v_stride,const rtc::Callback0<void> & no_longer_used)138 WrappedI420Buffer::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 
~WrappedI420Buffer()158 WrappedI420Buffer::~WrappedI420Buffer() {
159   no_longer_used_cb_();
160 }
161 
width() const162 int WrappedI420Buffer::width() const {
163   return width_;
164 }
165 
height() const166 int WrappedI420Buffer::height() const {
167   return height_;
168 }
169 
data(PlaneType type) const170 const 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 
stride(PlaneType type) const184 int 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 
native_handle() const198 void* WrappedI420Buffer::native_handle() const {
199   return nullptr;
200 }
201 
NativeToI420Buffer()202 rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
203   RTC_NOTREACHED();
204   return nullptr;
205 }
206 
ShallowCenterCrop(const rtc::scoped_refptr<VideoFrameBuffer> & buffer,int cropped_width,int cropped_height)207 rtc::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