blob: 6ce806e35e5b1a490c301fd9c18374954f9528a2 [file] [log] [blame]
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +00001/*
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
kjellander6f8ce062015-11-16 13:52:24 -080011#include "webrtc/common_video/include/video_frame_buffer.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000012
13#include "webrtc/base/checks.h"
perkj14f41442015-11-30 22:15:45 -080014#include "webrtc/base/keep_ref_until_done.h"
nisse7cc9cc02016-03-29 23:44:19 -070015#include "libyuv/convert.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000016
17// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
18static const int kBufferAlignment = 64;
19
20namespace webrtc {
21
hbos900f9752016-02-05 08:08:34 -080022namespace {
23
24int I420DataSize(int height, int stride_y, int stride_u, int stride_v) {
25 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2);
26}
27
28} // namespace
29
Magnus Jedvert3318f982015-08-26 16:06:21 +020030uint8_t* VideoFrameBuffer::MutableData(PlaneType type) {
31 RTC_NOTREACHED();
32 return nullptr;
33}
34
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000035VideoFrameBuffer::~VideoFrameBuffer() {}
36
37I420Buffer::I420Buffer(int width, int height)
38 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
39}
40
41I420Buffer::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(
hbos900f9752016-02-05 08:08:34 -080052 I420DataSize(height, stride_y, stride_u, stride_v),
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000053 kBufferAlignment))) {
henrikg91d6ede2015-09-17 00:24:34 -070054 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);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000059}
60
61I420Buffer::~I420Buffer() {
62}
63
hbos900f9752016-02-05 08:08:34 -080064void I420Buffer::InitializeData() {
65 memset(data_.get(), 0,
66 I420DataSize(height_, stride_y_, stride_u_, stride_v_));
67}
68
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000069int I420Buffer::width() const {
70 return width_;
71}
72
73int I420Buffer::height() const {
74 return height_;
75}
76
77const uint8_t* I420Buffer::data(PlaneType type) const {
78 switch (type) {
79 case kYPlane:
80 return data_.get();
81 case kUPlane:
82 return data_.get() + stride_y_ * height_;
83 case kVPlane:
84 return data_.get() + stride_y_ * height_ +
85 stride_u_ * ((height_ + 1) / 2);
86 default:
87 RTC_NOTREACHED();
88 return nullptr;
89 }
90}
91
Niels Möller47fe34c2016-04-18 13:02:59 +020092bool I420Buffer::IsMutable() {
93 return HasOneRef();
94}
95
Magnus Jedvert3318f982015-08-26 16:06:21 +020096uint8_t* I420Buffer::MutableData(PlaneType type) {
Niels Möller47fe34c2016-04-18 13:02:59 +020097 RTC_DCHECK(IsMutable());
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000098 return const_cast<uint8_t*>(
99 static_cast<const VideoFrameBuffer*>(this)->data(type));
100}
101
102int I420Buffer::stride(PlaneType type) const {
103 switch (type) {
104 case kYPlane:
105 return stride_y_;
106 case kUPlane:
107 return stride_u_;
108 case kVPlane:
109 return stride_v_;
110 default:
111 RTC_NOTREACHED();
112 return 0;
113 }
114}
115
Per9b3f56e2015-04-09 13:44:16 +0200116void* I420Buffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000117 return nullptr;
118}
119
Peter Boströmeb66e802015-06-05 11:08:03 +0200120rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
121 RTC_NOTREACHED();
122 return nullptr;
123}
124
nisse7cc9cc02016-03-29 23:44:19 -0700125rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
126 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
127 int width = buffer->width();
128 int height = buffer->height();
129 rtc::scoped_refptr<I420Buffer> copy =
130 new rtc::RefCountedObject<I420Buffer>(width, height);
131 RTC_CHECK(libyuv::I420Copy(buffer->data(kYPlane), buffer->stride(kYPlane),
132 buffer->data(kUPlane), buffer->stride(kUPlane),
133 buffer->data(kVPlane), buffer->stride(kVPlane),
134 copy->MutableData(kYPlane), copy->stride(kYPlane),
135 copy->MutableData(kUPlane), copy->stride(kUPlane),
136 copy->MutableData(kVPlane), copy->stride(kVPlane),
137 width, height) == 0);
138
139 return copy;
140}
141
Peter Boströmeb66e802015-06-05 11:08:03 +0200142NativeHandleBuffer::NativeHandleBuffer(void* native_handle,
143 int width,
144 int height)
145 : native_handle_(native_handle), width_(width), height_(height) {
henrikg91d6ede2015-09-17 00:24:34 -0700146 RTC_DCHECK(native_handle != nullptr);
147 RTC_DCHECK_GT(width, 0);
148 RTC_DCHECK_GT(height, 0);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000149}
150
Niels Möller47fe34c2016-04-18 13:02:59 +0200151bool NativeHandleBuffer::IsMutable() {
152 return false;
153}
154
Peter Boströmeb66e802015-06-05 11:08:03 +0200155int NativeHandleBuffer::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000156 return width_;
157}
158
Peter Boströmeb66e802015-06-05 11:08:03 +0200159int NativeHandleBuffer::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000160 return height_;
161}
162
Peter Boströmeb66e802015-06-05 11:08:03 +0200163const uint8_t* NativeHandleBuffer::data(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000164 RTC_NOTREACHED(); // Should not be called.
165 return nullptr;
166}
167
Peter Boströmeb66e802015-06-05 11:08:03 +0200168int NativeHandleBuffer::stride(PlaneType type) const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000169 RTC_NOTREACHED(); // Should not be called.
170 return 0;
171}
172
Peter Boströmeb66e802015-06-05 11:08:03 +0200173void* NativeHandleBuffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000174 return native_handle_;
175}
176
Magnus Jedvertc464f502015-08-25 23:22:08 +0200177WrappedI420Buffer::WrappedI420Buffer(int width,
Per33544192015-04-02 12:30:51 +0200178 int height,
179 const uint8_t* y_plane,
180 int y_stride,
181 const uint8_t* u_plane,
182 int u_stride,
183 const uint8_t* v_plane,
184 int v_stride,
185 const rtc::Callback0<void>& no_longer_used)
Magnus Jedvertc464f502015-08-25 23:22:08 +0200186 : width_(width),
187 height_(height),
188 y_plane_(y_plane),
189 u_plane_(u_plane),
190 v_plane_(v_plane),
191 y_stride_(y_stride),
192 u_stride_(u_stride),
193 v_stride_(v_stride),
194 no_longer_used_cb_(no_longer_used) {
Per33544192015-04-02 12:30:51 +0200195}
196
197WrappedI420Buffer::~WrappedI420Buffer() {
198 no_longer_used_cb_();
199}
200
Niels Möller47fe34c2016-04-18 13:02:59 +0200201// Data owned by creator; never mutable.
202bool WrappedI420Buffer::IsMutable() {
203 return false;
204}
205
Per33544192015-04-02 12:30:51 +0200206int WrappedI420Buffer::width() const {
207 return width_;
208}
209
210int WrappedI420Buffer::height() const {
211 return height_;
212}
213
214const uint8_t* WrappedI420Buffer::data(PlaneType type) const {
215 switch (type) {
216 case kYPlane:
217 return y_plane_;
218 case kUPlane:
219 return u_plane_;
220 case kVPlane:
221 return v_plane_;
222 default:
223 RTC_NOTREACHED();
224 return nullptr;
225 }
226}
227
Per33544192015-04-02 12:30:51 +0200228int WrappedI420Buffer::stride(PlaneType type) const {
229 switch (type) {
230 case kYPlane:
231 return y_stride_;
232 case kUPlane:
233 return u_stride_;
234 case kVPlane:
235 return v_stride_;
236 default:
237 RTC_NOTREACHED();
238 return 0;
239 }
240}
241
Per9b3f56e2015-04-09 13:44:16 +0200242void* WrappedI420Buffer::native_handle() const {
Per33544192015-04-02 12:30:51 +0200243 return nullptr;
244}
245
Peter Boströmeb66e802015-06-05 11:08:03 +0200246rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
247 RTC_NOTREACHED();
248 return nullptr;
249}
250
Magnus Jedvertc464f502015-08-25 23:22:08 +0200251rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop(
252 const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
253 int cropped_width,
254 int cropped_height) {
henrikg91d6ede2015-09-17 00:24:34 -0700255 RTC_CHECK(buffer->native_handle() == nullptr);
256 RTC_CHECK_LE(cropped_width, buffer->width());
257 RTC_CHECK_LE(cropped_height, buffer->height());
Magnus Jedvertc464f502015-08-25 23:22:08 +0200258 if (buffer->width() == cropped_width && buffer->height() == cropped_height)
259 return buffer;
260
261 // Center crop to |cropped_width| x |cropped_height|.
262 // Make sure offset is even so that u/v plane becomes aligned.
263 const int uv_offset_x = (buffer->width() - cropped_width) / 4;
264 const int uv_offset_y = (buffer->height() - cropped_height) / 4;
265 const int offset_x = uv_offset_x * 2;
266 const int offset_y = uv_offset_y * 2;
267
Magnus Jedvert3318f982015-08-26 16:06:21 +0200268 const uint8_t* y_plane = buffer->data(kYPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200269 buffer->stride(kYPlane) * offset_y + offset_x;
Magnus Jedvert3318f982015-08-26 16:06:21 +0200270 const uint8_t* u_plane = buffer->data(kUPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200271 buffer->stride(kUPlane) * uv_offset_y + uv_offset_x;
Magnus Jedvert3318f982015-08-26 16:06:21 +0200272 const uint8_t* v_plane = buffer->data(kVPlane) +
Magnus Jedvertc464f502015-08-25 23:22:08 +0200273 buffer->stride(kVPlane) * uv_offset_y + uv_offset_x;
274 return new rtc::RefCountedObject<WrappedI420Buffer>(
275 cropped_width, cropped_height,
276 y_plane, buffer->stride(kYPlane),
277 u_plane, buffer->stride(kUPlane),
278 v_plane, buffer->stride(kVPlane),
perkj14f41442015-11-30 22:15:45 -0800279 rtc::KeepRefUntilDone(buffer));
Magnus Jedvertc464f502015-08-25 23:22:08 +0200280}
281
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000282} // namespace webrtc