blob: 700dcaf02b7af098798eb51e344f065b232a8700 [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
nisse06176e42016-04-18 05:34:40 -070030const uint8_t* VideoFrameBuffer::data(PlaneType type) const {
31 switch (type) {
32 case kYPlane:
33 return DataY();
34 case kUPlane:
35 return DataU();
36 case kVPlane:
37 return DataV();
38 default:
39 RTC_NOTREACHED();
40 return nullptr;
41 }
42}
43
44const uint8_t* VideoFrameBuffer::DataY() const {
45 return data(kYPlane);
46}
47const uint8_t* VideoFrameBuffer::DataU() const {
48 return data(kUPlane);
49}
50const uint8_t* VideoFrameBuffer::DataV() const {
51 return data(kVPlane);
52}
53
54int VideoFrameBuffer::stride(PlaneType type) const {
55 switch (type) {
56 case kYPlane:
57 return StrideY();
58 case kUPlane:
59 return StrideU();
60 case kVPlane:
61 return StrideV();
62 default:
63 RTC_NOTREACHED();
64 return 0;
65 }
66}
67
68int VideoFrameBuffer::StrideY() const {
69 return stride(kYPlane);
70}
71int VideoFrameBuffer::StrideU() const {
72 return stride(kUPlane);
73}
74int VideoFrameBuffer::StrideV() const {
75 return stride(kVPlane);
76}
77
78uint8_t* VideoFrameBuffer::MutableDataY() {
Magnus Jedvert3318f982015-08-26 16:06:21 +020079 RTC_NOTREACHED();
80 return nullptr;
81}
nisse06176e42016-04-18 05:34:40 -070082uint8_t* VideoFrameBuffer::MutableDataU() {
83 RTC_NOTREACHED();
84 return nullptr;
85}
86uint8_t* VideoFrameBuffer::MutableDataV() {
87 RTC_NOTREACHED();
88 return nullptr;
89}
90
91uint8_t* VideoFrameBuffer::MutableData(PlaneType type) {
92 switch (type) {
93 case kYPlane:
94 return MutableDataY();
95 case kUPlane:
96 return MutableDataU();
97 case kVPlane:
98 return MutableDataV();
99 default:
100 RTC_NOTREACHED();
101 return nullptr;
102 }
103}
Magnus Jedvert3318f982015-08-26 16:06:21 +0200104
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000105VideoFrameBuffer::~VideoFrameBuffer() {}
106
107I420Buffer::I420Buffer(int width, int height)
108 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
109}
110
111I420Buffer::I420Buffer(int width,
112 int height,
113 int stride_y,
114 int stride_u,
115 int stride_v)
116 : width_(width),
117 height_(height),
118 stride_y_(stride_y),
119 stride_u_(stride_u),
120 stride_v_(stride_v),
121 data_(static_cast<uint8_t*>(AlignedMalloc(
hbos900f9752016-02-05 08:08:34 -0800122 I420DataSize(height, stride_y, stride_u, stride_v),
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000123 kBufferAlignment))) {
henrikg91d6ede2015-09-17 00:24:34 -0700124 RTC_DCHECK_GT(width, 0);
125 RTC_DCHECK_GT(height, 0);
126 RTC_DCHECK_GE(stride_y, width);
127 RTC_DCHECK_GE(stride_u, (width + 1) / 2);
128 RTC_DCHECK_GE(stride_v, (width + 1) / 2);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000129}
130
131I420Buffer::~I420Buffer() {
132}
133
hbos900f9752016-02-05 08:08:34 -0800134void I420Buffer::InitializeData() {
135 memset(data_.get(), 0,
136 I420DataSize(height_, stride_y_, stride_u_, stride_v_));
137}
138
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000139int I420Buffer::width() const {
140 return width_;
141}
142
143int I420Buffer::height() const {
144 return height_;
145}
146
nisse06176e42016-04-18 05:34:40 -0700147const uint8_t* I420Buffer::DataY() const {
148 return data_.get();
149}
150const uint8_t* I420Buffer::DataU() const {
151 return data_.get() + stride_y_ * height_;
152}
153const uint8_t* I420Buffer::DataV() const {
154 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000155}
156
Niels Möller47fe34c2016-04-18 13:02:59 +0200157bool I420Buffer::IsMutable() {
158 return HasOneRef();
159}
160
nisse06176e42016-04-18 05:34:40 -0700161uint8_t* I420Buffer::MutableDataY() {
Niels Möller47fe34c2016-04-18 13:02:59 +0200162 RTC_DCHECK(IsMutable());
nisse06176e42016-04-18 05:34:40 -0700163 return const_cast<uint8_t*>(DataY());
164}
165uint8_t* I420Buffer::MutableDataU() {
166 RTC_DCHECK(IsMutable());
167 return const_cast<uint8_t*>(DataU());
168}
169uint8_t* I420Buffer::MutableDataV() {
170 RTC_DCHECK(IsMutable());
171 return const_cast<uint8_t*>(DataV());
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000172}
173
nisse06176e42016-04-18 05:34:40 -0700174int I420Buffer::StrideY() const {
175 return stride_y_;
176}
177int I420Buffer::StrideU() const {
178 return stride_u_;
179}
180int I420Buffer::StrideV() const {
181 return stride_v_;
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000182}
183
Per9b3f56e2015-04-09 13:44:16 +0200184void* I420Buffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000185 return nullptr;
186}
187
Peter Boströmeb66e802015-06-05 11:08:03 +0200188rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
189 RTC_NOTREACHED();
190 return nullptr;
191}
192
nisse7cc9cc02016-03-29 23:44:19 -0700193rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
194 const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
195 int width = buffer->width();
196 int height = buffer->height();
197 rtc::scoped_refptr<I420Buffer> copy =
198 new rtc::RefCountedObject<I420Buffer>(width, height);
nisse06176e42016-04-18 05:34:40 -0700199 RTC_CHECK(libyuv::I420Copy(buffer->DataY(), buffer->StrideY(),
200 buffer->DataU(), buffer->StrideU(),
201 buffer->DataV(), buffer->StrideV(),
202 copy->MutableDataY(), copy->StrideY(),
203 copy->MutableDataU(), copy->StrideU(),
204 copy->MutableDataV(), copy->StrideV(),
nisse7cc9cc02016-03-29 23:44:19 -0700205 width, height) == 0);
206
207 return copy;
208}
209
Peter Boströmeb66e802015-06-05 11:08:03 +0200210NativeHandleBuffer::NativeHandleBuffer(void* native_handle,
211 int width,
212 int height)
213 : native_handle_(native_handle), width_(width), height_(height) {
henrikg91d6ede2015-09-17 00:24:34 -0700214 RTC_DCHECK(native_handle != nullptr);
215 RTC_DCHECK_GT(width, 0);
216 RTC_DCHECK_GT(height, 0);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000217}
218
Niels Möller47fe34c2016-04-18 13:02:59 +0200219bool NativeHandleBuffer::IsMutable() {
220 return false;
221}
222
Peter Boströmeb66e802015-06-05 11:08:03 +0200223int NativeHandleBuffer::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000224 return width_;
225}
226
Peter Boströmeb66e802015-06-05 11:08:03 +0200227int NativeHandleBuffer::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000228 return height_;
229}
230
nisse06176e42016-04-18 05:34:40 -0700231const uint8_t* NativeHandleBuffer::DataY() const {
232 RTC_NOTREACHED(); // Should not be called.
233 return nullptr;
234}
235const uint8_t* NativeHandleBuffer::DataU() const {
236 RTC_NOTREACHED(); // Should not be called.
237 return nullptr;
238}
239const uint8_t* NativeHandleBuffer::DataV() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000240 RTC_NOTREACHED(); // Should not be called.
241 return nullptr;
242}
243
nisse06176e42016-04-18 05:34:40 -0700244int NativeHandleBuffer::StrideY() const {
245 RTC_NOTREACHED(); // Should not be called.
246 return 0;
247}
248int NativeHandleBuffer::StrideU() const {
249 RTC_NOTREACHED(); // Should not be called.
250 return 0;
251}
252int NativeHandleBuffer::StrideV() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000253 RTC_NOTREACHED(); // Should not be called.
254 return 0;
255}
256
Peter Boströmeb66e802015-06-05 11:08:03 +0200257void* NativeHandleBuffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000258 return native_handle_;
259}
260
Magnus Jedvertc464f502015-08-25 23:22:08 +0200261WrappedI420Buffer::WrappedI420Buffer(int width,
Per33544192015-04-02 12:30:51 +0200262 int height,
263 const uint8_t* y_plane,
264 int y_stride,
265 const uint8_t* u_plane,
266 int u_stride,
267 const uint8_t* v_plane,
268 int v_stride,
269 const rtc::Callback0<void>& no_longer_used)
Magnus Jedvertc464f502015-08-25 23:22:08 +0200270 : width_(width),
271 height_(height),
272 y_plane_(y_plane),
273 u_plane_(u_plane),
274 v_plane_(v_plane),
275 y_stride_(y_stride),
276 u_stride_(u_stride),
277 v_stride_(v_stride),
278 no_longer_used_cb_(no_longer_used) {
Per33544192015-04-02 12:30:51 +0200279}
280
281WrappedI420Buffer::~WrappedI420Buffer() {
282 no_longer_used_cb_();
283}
284
Niels Möller47fe34c2016-04-18 13:02:59 +0200285// Data owned by creator; never mutable.
286bool WrappedI420Buffer::IsMutable() {
287 return false;
288}
289
Per33544192015-04-02 12:30:51 +0200290int WrappedI420Buffer::width() const {
291 return width_;
292}
293
294int WrappedI420Buffer::height() const {
295 return height_;
296}
297
nisse06176e42016-04-18 05:34:40 -0700298const uint8_t* WrappedI420Buffer::DataY() const {
299 return y_plane_;
300}
301const uint8_t* WrappedI420Buffer::DataU() const {
302 return u_plane_;
303}
304const uint8_t* WrappedI420Buffer::DataV() const {
305 return v_plane_;
Per33544192015-04-02 12:30:51 +0200306}
307
nisse06176e42016-04-18 05:34:40 -0700308int WrappedI420Buffer::StrideY() const {
309 return y_stride_;
310}
311int WrappedI420Buffer::StrideU() const {
312 return u_stride_;
313}
314int WrappedI420Buffer::StrideV() const {
315 return v_stride_;
Per33544192015-04-02 12:30:51 +0200316}
317
Per9b3f56e2015-04-09 13:44:16 +0200318void* WrappedI420Buffer::native_handle() const {
Per33544192015-04-02 12:30:51 +0200319 return nullptr;
320}
321
Peter Boströmeb66e802015-06-05 11:08:03 +0200322rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
323 RTC_NOTREACHED();
324 return nullptr;
325}
326
Magnus Jedvertc464f502015-08-25 23:22:08 +0200327rtc::scoped_refptr<VideoFrameBuffer> ShallowCenterCrop(
328 const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
329 int cropped_width,
330 int cropped_height) {
henrikg91d6ede2015-09-17 00:24:34 -0700331 RTC_CHECK(buffer->native_handle() == nullptr);
332 RTC_CHECK_LE(cropped_width, buffer->width());
333 RTC_CHECK_LE(cropped_height, buffer->height());
Magnus Jedvertc464f502015-08-25 23:22:08 +0200334 if (buffer->width() == cropped_width && buffer->height() == cropped_height)
335 return buffer;
336
337 // Center crop to |cropped_width| x |cropped_height|.
338 // Make sure offset is even so that u/v plane becomes aligned.
339 const int uv_offset_x = (buffer->width() - cropped_width) / 4;
340 const int uv_offset_y = (buffer->height() - cropped_height) / 4;
341 const int offset_x = uv_offset_x * 2;
342 const int offset_y = uv_offset_y * 2;
343
nisse06176e42016-04-18 05:34:40 -0700344 const uint8_t* y_plane = buffer->DataY() +
345 buffer->StrideY() * offset_y + offset_x;
346 const uint8_t* u_plane = buffer->DataU() +
347 buffer->StrideU() * uv_offset_y + uv_offset_x;
348 const uint8_t* v_plane = buffer->DataV() +
349 buffer->StrideV() * uv_offset_y + uv_offset_x;
Magnus Jedvertc464f502015-08-25 23:22:08 +0200350 return new rtc::RefCountedObject<WrappedI420Buffer>(
351 cropped_width, cropped_height,
nisse06176e42016-04-18 05:34:40 -0700352 y_plane, buffer->StrideY(),
353 u_plane, buffer->StrideU(),
354 v_plane, buffer->StrideV(),
perkj14f41442015-11-30 22:15:45 -0800355 rtc::KeepRefUntilDone(buffer));
Magnus Jedvertc464f502015-08-25 23:22:08 +0200356}
357
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000358} // namespace webrtc