blob: fd20e564f5e5bf855a331393d4f443975f3e8867 [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
Niels Möller718a7632016-06-13 13:06:01 +020011#include <algorithm>
12
kjellander6f8ce062015-11-16 13:52:24 -080013#include "webrtc/common_video/include/video_frame_buffer.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000014
15#include "webrtc/base/checks.h"
perkj14f41442015-11-30 22:15:45 -080016#include "webrtc/base/keep_ref_until_done.h"
nisse7cc9cc02016-03-29 23:44:19 -070017#include "libyuv/convert.h"
fbarchardd1f83cf2016-07-08 17:33:20 -070018#include "libyuv/planar_functions.h"
Niels Möller718a7632016-06-13 13:06:01 +020019#include "libyuv/scale.h"
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000020
21// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
22static const int kBufferAlignment = 64;
23
24namespace webrtc {
25
hbos900f9752016-02-05 08:08:34 -080026namespace {
27
28int I420DataSize(int height, int stride_y, int stride_u, int stride_v) {
29 return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2);
30}
31
32} // namespace
33
nisse06176e42016-04-18 05:34:40 -070034uint8_t* VideoFrameBuffer::MutableDataY() {
Magnus Jedvert3318f982015-08-26 16:06:21 +020035 RTC_NOTREACHED();
36 return nullptr;
37}
nisse06176e42016-04-18 05:34:40 -070038uint8_t* VideoFrameBuffer::MutableDataU() {
39 RTC_NOTREACHED();
40 return nullptr;
41}
42uint8_t* VideoFrameBuffer::MutableDataV() {
43 RTC_NOTREACHED();
44 return nullptr;
45}
46
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000047VideoFrameBuffer::~VideoFrameBuffer() {}
48
49I420Buffer::I420Buffer(int width, int height)
50 : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
51}
52
53I420Buffer::I420Buffer(int width,
54 int height,
55 int stride_y,
56 int stride_u,
57 int stride_v)
58 : width_(width),
59 height_(height),
60 stride_y_(stride_y),
61 stride_u_(stride_u),
62 stride_v_(stride_v),
63 data_(static_cast<uint8_t*>(AlignedMalloc(
hbos900f9752016-02-05 08:08:34 -080064 I420DataSize(height, stride_y, stride_u, stride_v),
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000065 kBufferAlignment))) {
henrikg91d6ede2015-09-17 00:24:34 -070066 RTC_DCHECK_GT(width, 0);
67 RTC_DCHECK_GT(height, 0);
68 RTC_DCHECK_GE(stride_y, width);
69 RTC_DCHECK_GE(stride_u, (width + 1) / 2);
70 RTC_DCHECK_GE(stride_v, (width + 1) / 2);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000071}
72
73I420Buffer::~I420Buffer() {
74}
75
nisseac62bd42016-06-20 03:38:52 -070076rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, int height) {
77 return new rtc::RefCountedObject<I420Buffer>(width, height);
78}
79
80rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width,
81 int height,
82 int stride_y,
83 int stride_u,
84 int stride_v) {
85 return new rtc::RefCountedObject<I420Buffer>(
86 width, height, stride_y, stride_u, stride_v);
87}
88
hbos900f9752016-02-05 08:08:34 -080089void I420Buffer::InitializeData() {
90 memset(data_.get(), 0,
91 I420DataSize(height_, stride_y_, stride_u_, stride_v_));
92}
93
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000094int I420Buffer::width() const {
95 return width_;
96}
97
98int I420Buffer::height() const {
99 return height_;
100}
101
nisse06176e42016-04-18 05:34:40 -0700102const uint8_t* I420Buffer::DataY() const {
103 return data_.get();
104}
105const uint8_t* I420Buffer::DataU() const {
106 return data_.get() + stride_y_ * height_;
107}
108const uint8_t* I420Buffer::DataV() const {
109 return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000110}
111
nisse06176e42016-04-18 05:34:40 -0700112uint8_t* I420Buffer::MutableDataY() {
nisse06176e42016-04-18 05:34:40 -0700113 return const_cast<uint8_t*>(DataY());
114}
115uint8_t* I420Buffer::MutableDataU() {
nisse06176e42016-04-18 05:34:40 -0700116 return const_cast<uint8_t*>(DataU());
117}
118uint8_t* I420Buffer::MutableDataV() {
nisse06176e42016-04-18 05:34:40 -0700119 return const_cast<uint8_t*>(DataV());
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000120}
121
nisse06176e42016-04-18 05:34:40 -0700122int I420Buffer::StrideY() const {
123 return stride_y_;
124}
125int I420Buffer::StrideU() const {
126 return stride_u_;
127}
128int I420Buffer::StrideV() const {
129 return stride_v_;
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000130}
131
Per9b3f56e2015-04-09 13:44:16 +0200132void* I420Buffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000133 return nullptr;
134}
135
Peter Boströmeb66e802015-06-05 11:08:03 +0200136rtc::scoped_refptr<VideoFrameBuffer> I420Buffer::NativeToI420Buffer() {
137 RTC_NOTREACHED();
138 return nullptr;
139}
140
nisse7cc9cc02016-03-29 23:44:19 -0700141rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
Niels Möller6af2e862016-06-17 09:12:44 +0200142 const rtc::scoped_refptr<VideoFrameBuffer>& source) {
143 int width = source->width();
144 int height = source->height();
nisseac62bd42016-06-20 03:38:52 -0700145 rtc::scoped_refptr<I420Buffer> target = I420Buffer::Create(width, height);
Niels Möller6af2e862016-06-17 09:12:44 +0200146 RTC_CHECK(libyuv::I420Copy(source->DataY(), source->StrideY(),
147 source->DataU(), source->StrideU(),
148 source->DataV(), source->StrideV(),
149 target->MutableDataY(), target->StrideY(),
150 target->MutableDataU(), target->StrideU(),
151 target->MutableDataV(), target->StrideV(),
nisse7cc9cc02016-03-29 23:44:19 -0700152 width, height) == 0);
153
Niels Möller6af2e862016-06-17 09:12:44 +0200154 return target;
nisse7cc9cc02016-03-29 23:44:19 -0700155}
156
nisseefec5902016-06-09 00:31:39 -0700157void I420Buffer::SetToBlack() {
158 RTC_CHECK(libyuv::I420Rect(MutableDataY(), StrideY(),
159 MutableDataU(), StrideU(),
160 MutableDataV(), StrideV(),
161 0, 0, width(), height(),
162 0, 128, 128) == 0);
163}
164
Niels Möller718a7632016-06-13 13:06:01 +0200165void I420Buffer::CropAndScaleFrom(
166 const rtc::scoped_refptr<VideoFrameBuffer>& src,
167 int offset_x,
168 int offset_y,
169 int crop_width,
170 int crop_height) {
171 RTC_CHECK_LE(crop_width, src->width());
172 RTC_CHECK_LE(crop_height, src->height());
173 RTC_CHECK_LE(crop_width + offset_x, src->width());
174 RTC_CHECK_LE(crop_height + offset_y, src->height());
175 RTC_CHECK_GE(offset_x, 0);
176 RTC_CHECK_GE(offset_y, 0);
177
178 // Make sure offset is even so that u/v plane becomes aligned.
179 const int uv_offset_x = offset_x / 2;
180 const int uv_offset_y = offset_y / 2;
181 offset_x = uv_offset_x * 2;
182 offset_y = uv_offset_y * 2;
183
184 const uint8_t* y_plane =
185 src->DataY() + src->StrideY() * offset_y + offset_x;
186 const uint8_t* u_plane =
187 src->DataU() + src->StrideU() * uv_offset_y + uv_offset_x;
188 const uint8_t* v_plane =
189 src->DataV() + src->StrideV() * uv_offset_y + uv_offset_x;
190 int res = libyuv::I420Scale(y_plane, src->StrideY(),
191 u_plane, src->StrideU(),
192 v_plane, src->StrideV(),
193 crop_width, crop_height,
194 MutableDataY(), StrideY(),
195 MutableDataU(), StrideU(),
196 MutableDataV(), StrideV(),
197 width(), height(), libyuv::kFilterBox);
198
199 RTC_DCHECK_EQ(res, 0);
200}
201
202void I420Buffer::CropAndScaleFrom(
203 const rtc::scoped_refptr<VideoFrameBuffer>& src) {
204 const int crop_width =
205 std::min(src->width(), width() * src->height() / height());
206 const int crop_height =
207 std::min(src->height(), height() * src->width() / width());
208
209 CropAndScaleFrom(
210 src,
211 (src->width() - crop_width) / 2, (src->height() - crop_height) / 2,
212 crop_width, crop_height);
213}
214
215void I420Buffer::ScaleFrom(const rtc::scoped_refptr<VideoFrameBuffer>& src) {
216 CropAndScaleFrom(src, 0, 0, src->width(), src->height());
217}
218
Niels Möller6af2e862016-06-17 09:12:44 +0200219rtc::scoped_refptr<I420Buffer> I420Buffer::CopyKeepStride(
220 const rtc::scoped_refptr<VideoFrameBuffer>& source) {
221 int width = source->width();
222 int height = source->height();
223 int stride_y = source->StrideY();
224 int stride_u = source->StrideU();
225 int stride_v = source->StrideV();
226 rtc::scoped_refptr<I420Buffer> target =
nisseac62bd42016-06-20 03:38:52 -0700227 I420Buffer::Create(width, height, stride_y, stride_u, stride_v);
Niels Möller6af2e862016-06-17 09:12:44 +0200228 RTC_CHECK(libyuv::I420Copy(source->DataY(), stride_y,
229 source->DataU(), stride_u,
230 source->DataV(), stride_v,
231 target->MutableDataY(), stride_y,
232 target->MutableDataU(), stride_u,
233 target->MutableDataV(), stride_v,
234 width, height) == 0);
235
236 return target;
237}
238
Peter Boströmeb66e802015-06-05 11:08:03 +0200239NativeHandleBuffer::NativeHandleBuffer(void* native_handle,
240 int width,
241 int height)
242 : native_handle_(native_handle), width_(width), height_(height) {
henrikg91d6ede2015-09-17 00:24:34 -0700243 RTC_DCHECK(native_handle != nullptr);
244 RTC_DCHECK_GT(width, 0);
245 RTC_DCHECK_GT(height, 0);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000246}
247
Peter Boströmeb66e802015-06-05 11:08:03 +0200248int NativeHandleBuffer::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000249 return width_;
250}
251
Peter Boströmeb66e802015-06-05 11:08:03 +0200252int NativeHandleBuffer::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000253 return height_;
254}
255
nisse06176e42016-04-18 05:34:40 -0700256const uint8_t* NativeHandleBuffer::DataY() const {
257 RTC_NOTREACHED(); // Should not be called.
258 return nullptr;
259}
260const uint8_t* NativeHandleBuffer::DataU() const {
261 RTC_NOTREACHED(); // Should not be called.
262 return nullptr;
263}
264const uint8_t* NativeHandleBuffer::DataV() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000265 RTC_NOTREACHED(); // Should not be called.
266 return nullptr;
267}
268
nisse06176e42016-04-18 05:34:40 -0700269int NativeHandleBuffer::StrideY() const {
270 RTC_NOTREACHED(); // Should not be called.
271 return 0;
272}
273int NativeHandleBuffer::StrideU() const {
274 RTC_NOTREACHED(); // Should not be called.
275 return 0;
276}
277int NativeHandleBuffer::StrideV() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000278 RTC_NOTREACHED(); // Should not be called.
279 return 0;
280}
281
Peter Boströmeb66e802015-06-05 11:08:03 +0200282void* NativeHandleBuffer::native_handle() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000283 return native_handle_;
284}
285
Magnus Jedvertc464f502015-08-25 23:22:08 +0200286WrappedI420Buffer::WrappedI420Buffer(int width,
Per33544192015-04-02 12:30:51 +0200287 int height,
288 const uint8_t* y_plane,
289 int y_stride,
290 const uint8_t* u_plane,
291 int u_stride,
292 const uint8_t* v_plane,
293 int v_stride,
294 const rtc::Callback0<void>& no_longer_used)
Magnus Jedvertc464f502015-08-25 23:22:08 +0200295 : width_(width),
296 height_(height),
297 y_plane_(y_plane),
298 u_plane_(u_plane),
299 v_plane_(v_plane),
300 y_stride_(y_stride),
301 u_stride_(u_stride),
302 v_stride_(v_stride),
303 no_longer_used_cb_(no_longer_used) {
Per33544192015-04-02 12:30:51 +0200304}
305
306WrappedI420Buffer::~WrappedI420Buffer() {
307 no_longer_used_cb_();
308}
309
Per33544192015-04-02 12:30:51 +0200310int WrappedI420Buffer::width() const {
311 return width_;
312}
313
314int WrappedI420Buffer::height() const {
315 return height_;
316}
317
nisse06176e42016-04-18 05:34:40 -0700318const uint8_t* WrappedI420Buffer::DataY() const {
319 return y_plane_;
320}
321const uint8_t* WrappedI420Buffer::DataU() const {
322 return u_plane_;
323}
324const uint8_t* WrappedI420Buffer::DataV() const {
325 return v_plane_;
Per33544192015-04-02 12:30:51 +0200326}
327
nisse06176e42016-04-18 05:34:40 -0700328int WrappedI420Buffer::StrideY() const {
329 return y_stride_;
330}
331int WrappedI420Buffer::StrideU() const {
332 return u_stride_;
333}
334int WrappedI420Buffer::StrideV() const {
335 return v_stride_;
Per33544192015-04-02 12:30:51 +0200336}
337
Per9b3f56e2015-04-09 13:44:16 +0200338void* WrappedI420Buffer::native_handle() const {
Per33544192015-04-02 12:30:51 +0200339 return nullptr;
340}
341
Peter Boströmeb66e802015-06-05 11:08:03 +0200342rtc::scoped_refptr<VideoFrameBuffer> WrappedI420Buffer::NativeToI420Buffer() {
343 RTC_NOTREACHED();
344 return nullptr;
345}
346
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000347} // namespace webrtc