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 |