2 * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
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.
10 #include "api/video/i410_buffer.h"
17 #include "api/make_ref_counted.h"
18 #include "api/video/i420_buffer.h"
19 #include "rtc_base/checks.h"
20 #include "third_party/libyuv/include/libyuv/convert.h"
21 #include "third_party/libyuv/include/libyuv/planar_functions.h"
22 #include "third_party/libyuv/include/libyuv/scale.h"
24 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
25 static const int kBufferAlignment
= 64;
26 static const int kBytesPerPixel
= 2;
32 int I410DataSize(int height
, int stride_y
, int stride_u
, int stride_v
) {
33 return kBytesPerPixel
*
34 (stride_y
* height
+ stride_u
* height
+ stride_v
* height
);
39 I410Buffer::I410Buffer(int width
, int height
)
40 : I410Buffer(width
, height
, width
, width
, width
) {}
42 I410Buffer::I410Buffer(int width
,
52 data_(static_cast<uint16_t*>(
53 AlignedMalloc(I410DataSize(height
, stride_y
, stride_u
, stride_v
),
55 RTC_DCHECK_GT(width
, 0);
56 RTC_DCHECK_GT(height
, 0);
57 RTC_DCHECK_GE(stride_y
, width
);
58 RTC_DCHECK_GE(stride_u
, width
);
59 RTC_DCHECK_GE(stride_v
, width
);
62 I410Buffer::~I410Buffer() {}
65 rtc::scoped_refptr
<I410Buffer
> I410Buffer::Create(int width
, int height
) {
66 return rtc::make_ref_counted
<I410Buffer
>(width
, height
);
70 rtc::scoped_refptr
<I410Buffer
> I410Buffer::Create(int width
,
75 return rtc::make_ref_counted
<I410Buffer
>(width
, height
, stride_y
, stride_u
,
80 rtc::scoped_refptr
<I410Buffer
> I410Buffer::Copy(
81 const I410BufferInterface
& source
) {
82 return Copy(source
.width(), source
.height(), source
.DataY(), source
.StrideY(),
83 source
.DataU(), source
.StrideU(), source
.DataV(),
88 rtc::scoped_refptr
<I410Buffer
> I410Buffer::Copy(int width
,
90 const uint16_t* data_y
,
92 const uint16_t* data_u
,
94 const uint16_t* data_v
,
96 // Note: May use different strides than the input data.
97 rtc::scoped_refptr
<I410Buffer
> buffer
= Create(width
, height
);
98 int res
= libyuv::I410Copy(data_y
, stride_y
, data_u
, stride_u
, data_v
,
99 stride_v
, buffer
->MutableDataY(),
100 buffer
->StrideY(), buffer
->MutableDataU(),
101 buffer
->StrideU(), buffer
->MutableDataV(),
102 buffer
->StrideV(), width
, height
);
103 RTC_DCHECK_EQ(res
, 0);
109 rtc::scoped_refptr
<I410Buffer
> I410Buffer::Rotate(
110 const I410BufferInterface
& src
,
111 VideoRotation rotation
) {
112 RTC_CHECK(src
.DataY());
113 RTC_CHECK(src
.DataU());
114 RTC_CHECK(src
.DataV());
116 int rotated_width
= src
.width();
117 int rotated_height
= src
.height();
118 if (rotation
== webrtc::kVideoRotation_90
||
119 rotation
== webrtc::kVideoRotation_270
) {
120 std::swap(rotated_width
, rotated_height
);
123 rtc::scoped_refptr
<webrtc::I410Buffer
> buffer
=
124 I410Buffer::Create(rotated_width
, rotated_height
);
126 int res
= libyuv::I410Rotate(
127 src
.DataY(), src
.StrideY(), src
.DataU(), src
.StrideU(), src
.DataV(),
128 src
.StrideV(), buffer
->MutableDataY(), buffer
->StrideY(),
129 buffer
->MutableDataU(), buffer
->StrideU(), buffer
->MutableDataV(),
130 buffer
->StrideV(), src
.width(), src
.height(),
131 static_cast<libyuv::RotationMode
>(rotation
));
132 RTC_DCHECK_EQ(res
, 0);
137 rtc::scoped_refptr
<I420BufferInterface
> I410Buffer::ToI420() {
138 rtc::scoped_refptr
<I420Buffer
> i420_buffer
=
139 I420Buffer::Create(width(), height());
140 int res
= libyuv::I410ToI420(
141 DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
142 i420_buffer
->MutableDataY(), i420_buffer
->StrideY(),
143 i420_buffer
->MutableDataU(), i420_buffer
->StrideU(),
144 i420_buffer
->MutableDataV(), i420_buffer
->StrideV(), width(), height());
145 RTC_DCHECK_EQ(res
, 0);
150 void I410Buffer::InitializeData() {
151 memset(data_
.get(), 0,
152 I410DataSize(height_
, stride_y_
, stride_u_
, stride_v_
));
155 int I410Buffer::width() const {
159 int I410Buffer::height() const {
163 const uint16_t* I410Buffer::DataY() const {
166 const uint16_t* I410Buffer::DataU() const {
167 return data_
.get() + stride_y_
* height_
;
169 const uint16_t* I410Buffer::DataV() const {
170 return data_
.get() + stride_y_
* height_
+ stride_u_
* height_
;
173 int I410Buffer::StrideY() const {
176 int I410Buffer::StrideU() const {
179 int I410Buffer::StrideV() const {
183 uint16_t* I410Buffer::MutableDataY() {
184 return const_cast<uint16_t*>(DataY());
186 uint16_t* I410Buffer::MutableDataU() {
187 return const_cast<uint16_t*>(DataU());
189 uint16_t* I410Buffer::MutableDataV() {
190 return const_cast<uint16_t*>(DataV());
193 void I410Buffer::CropAndScaleFrom(const I410BufferInterface
& src
,
198 RTC_CHECK_LE(crop_width
, src
.width());
199 RTC_CHECK_LE(crop_height
, src
.height());
200 RTC_CHECK_LE(crop_width
+ offset_x
, src
.width());
201 RTC_CHECK_LE(crop_height
+ offset_y
, src
.height());
202 RTC_CHECK_GE(offset_x
, 0);
203 RTC_CHECK_GE(offset_y
, 0);
205 const uint16_t* y_plane
= src
.DataY() + src
.StrideY() * offset_y
+ offset_x
;
206 const uint16_t* u_plane
= src
.DataU() + src
.StrideU() * offset_y
+ offset_x
;
207 const uint16_t* v_plane
= src
.DataV() + src
.StrideV() * offset_y
+ offset_x
;
208 int res
= libyuv::I444Scale_16(
209 y_plane
, src
.StrideY(), u_plane
, src
.StrideU(), v_plane
, src
.StrideV(),
210 crop_width
, crop_height
, MutableDataY(), StrideY(), MutableDataU(),
211 StrideU(), MutableDataV(), StrideV(), width(), height(),
214 RTC_DCHECK_EQ(res
, 0);
217 void I410Buffer::ScaleFrom(const I410BufferInterface
& src
) {
218 CropAndScaleFrom(src
, 0, 0, src
.width(), src
.height());
221 } // namespace webrtc