1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker #include "api/video/i210_buffer.h"
11*d9f75844SAndroid Build Coastguard Worker
12*d9f75844SAndroid Build Coastguard Worker #include <utility>
13*d9f75844SAndroid Build Coastguard Worker
14*d9f75844SAndroid Build Coastguard Worker #include "api/make_ref_counted.h"
15*d9f75844SAndroid Build Coastguard Worker #include "api/video/i420_buffer.h"
16*d9f75844SAndroid Build Coastguard Worker #include "api/video/i422_buffer.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
18*d9f75844SAndroid Build Coastguard Worker #include "third_party/libyuv/include/libyuv/convert.h"
19*d9f75844SAndroid Build Coastguard Worker #include "third_party/libyuv/include/libyuv/scale.h"
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
22*d9f75844SAndroid Build Coastguard Worker static const int kBufferAlignment = 64;
23*d9f75844SAndroid Build Coastguard Worker static const int kBytesPerPixel = 2;
24*d9f75844SAndroid Build Coastguard Worker
25*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
26*d9f75844SAndroid Build Coastguard Worker
27*d9f75844SAndroid Build Coastguard Worker namespace {
28*d9f75844SAndroid Build Coastguard Worker
I210DataSize(int height,int stride_y,int stride_u,int stride_v)29*d9f75844SAndroid Build Coastguard Worker int I210DataSize(int height, int stride_y, int stride_u, int stride_v) {
30*d9f75844SAndroid Build Coastguard Worker return kBytesPerPixel *
31*d9f75844SAndroid Build Coastguard Worker (stride_y * height + stride_u * height + stride_v * height);
32*d9f75844SAndroid Build Coastguard Worker }
33*d9f75844SAndroid Build Coastguard Worker
webrtcRotatePlane90_16(const uint16_t * src,int src_stride,uint16_t * dst,int dst_stride,int width,int height)34*d9f75844SAndroid Build Coastguard Worker void webrtcRotatePlane90_16(const uint16_t* src,
35*d9f75844SAndroid Build Coastguard Worker int src_stride,
36*d9f75844SAndroid Build Coastguard Worker uint16_t* dst,
37*d9f75844SAndroid Build Coastguard Worker int dst_stride,
38*d9f75844SAndroid Build Coastguard Worker int width,
39*d9f75844SAndroid Build Coastguard Worker int height) {
40*d9f75844SAndroid Build Coastguard Worker for (int x = 0; x < width; x++) {
41*d9f75844SAndroid Build Coastguard Worker for (int y = 0; y < height; y++) {
42*d9f75844SAndroid Build Coastguard Worker int dest_x = height - y - 1;
43*d9f75844SAndroid Build Coastguard Worker int dest_y = x;
44*d9f75844SAndroid Build Coastguard Worker dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
45*d9f75844SAndroid Build Coastguard Worker }
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker }
48*d9f75844SAndroid Build Coastguard Worker
webrtcRotatePlane180_16(const uint16_t * src,int src_stride,uint16_t * dst,int dst_stride,int width,int height)49*d9f75844SAndroid Build Coastguard Worker void webrtcRotatePlane180_16(const uint16_t* src,
50*d9f75844SAndroid Build Coastguard Worker int src_stride,
51*d9f75844SAndroid Build Coastguard Worker uint16_t* dst,
52*d9f75844SAndroid Build Coastguard Worker int dst_stride,
53*d9f75844SAndroid Build Coastguard Worker int width,
54*d9f75844SAndroid Build Coastguard Worker int height) {
55*d9f75844SAndroid Build Coastguard Worker for (int x = 0; x < width; x++) {
56*d9f75844SAndroid Build Coastguard Worker for (int y = 0; y < height; y++) {
57*d9f75844SAndroid Build Coastguard Worker int dest_x = width - x - 1;
58*d9f75844SAndroid Build Coastguard Worker int dest_y = height - y - 1;
59*d9f75844SAndroid Build Coastguard Worker dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
60*d9f75844SAndroid Build Coastguard Worker }
61*d9f75844SAndroid Build Coastguard Worker }
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker
webrtcRotatePlane270_16(const uint16_t * src,int src_stride,uint16_t * dst,int dst_stride,int width,int height)64*d9f75844SAndroid Build Coastguard Worker void webrtcRotatePlane270_16(const uint16_t* src,
65*d9f75844SAndroid Build Coastguard Worker int src_stride,
66*d9f75844SAndroid Build Coastguard Worker uint16_t* dst,
67*d9f75844SAndroid Build Coastguard Worker int dst_stride,
68*d9f75844SAndroid Build Coastguard Worker int width,
69*d9f75844SAndroid Build Coastguard Worker int height) {
70*d9f75844SAndroid Build Coastguard Worker for (int x = 0; x < width; x++) {
71*d9f75844SAndroid Build Coastguard Worker for (int y = 0; y < height; y++) {
72*d9f75844SAndroid Build Coastguard Worker int dest_x = y;
73*d9f75844SAndroid Build Coastguard Worker int dest_y = width - x - 1;
74*d9f75844SAndroid Build Coastguard Worker dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker }
77*d9f75844SAndroid Build Coastguard Worker }
78*d9f75844SAndroid Build Coastguard Worker
79*d9f75844SAndroid Build Coastguard Worker // TODO([email protected]): Remove as soon it is available in
80*d9f75844SAndroid Build Coastguard Worker // libyuv. Due to the rotate&scale required, this function may not be merged in
81*d9f75844SAndroid Build Coastguard Worker // to libyuv inmediatelly.
82*d9f75844SAndroid Build Coastguard Worker // https://bugs.chromium.org/p/libyuv/issues/detail?id=926
83*d9f75844SAndroid Build Coastguard Worker // This method assumes continuous allocation of the y-plane, possibly clobbering
84*d9f75844SAndroid Build Coastguard Worker // any padding between pixel rows.
webrtcI210Rotate(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint16_t * dst_y,int dst_stride_y,uint16_t * dst_u,int dst_stride_u,uint16_t * dst_v,int dst_stride_v,int width,int height,enum libyuv::RotationMode mode)85*d9f75844SAndroid Build Coastguard Worker int webrtcI210Rotate(const uint16_t* src_y,
86*d9f75844SAndroid Build Coastguard Worker int src_stride_y,
87*d9f75844SAndroid Build Coastguard Worker const uint16_t* src_u,
88*d9f75844SAndroid Build Coastguard Worker int src_stride_u,
89*d9f75844SAndroid Build Coastguard Worker const uint16_t* src_v,
90*d9f75844SAndroid Build Coastguard Worker int src_stride_v,
91*d9f75844SAndroid Build Coastguard Worker uint16_t* dst_y,
92*d9f75844SAndroid Build Coastguard Worker int dst_stride_y,
93*d9f75844SAndroid Build Coastguard Worker uint16_t* dst_u,
94*d9f75844SAndroid Build Coastguard Worker int dst_stride_u,
95*d9f75844SAndroid Build Coastguard Worker uint16_t* dst_v,
96*d9f75844SAndroid Build Coastguard Worker int dst_stride_v,
97*d9f75844SAndroid Build Coastguard Worker int width,
98*d9f75844SAndroid Build Coastguard Worker int height,
99*d9f75844SAndroid Build Coastguard Worker enum libyuv::RotationMode mode) {
100*d9f75844SAndroid Build Coastguard Worker int halfwidth = (width + 1) >> 1;
101*d9f75844SAndroid Build Coastguard Worker int halfheight = (height + 1) >> 1;
102*d9f75844SAndroid Build Coastguard Worker if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
103*d9f75844SAndroid Build Coastguard Worker !dst_u || !dst_v || dst_stride_y < 0) {
104*d9f75844SAndroid Build Coastguard Worker return -1;
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker // Negative height means invert the image.
107*d9f75844SAndroid Build Coastguard Worker if (height < 0) {
108*d9f75844SAndroid Build Coastguard Worker height = -height;
109*d9f75844SAndroid Build Coastguard Worker src_y = src_y + (height - 1) * src_stride_y;
110*d9f75844SAndroid Build Coastguard Worker src_u = src_u + (height - 1) * src_stride_u;
111*d9f75844SAndroid Build Coastguard Worker src_v = src_v + (height - 1) * src_stride_v;
112*d9f75844SAndroid Build Coastguard Worker src_stride_y = -src_stride_y;
113*d9f75844SAndroid Build Coastguard Worker src_stride_u = -src_stride_u;
114*d9f75844SAndroid Build Coastguard Worker src_stride_v = -src_stride_v;
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker
117*d9f75844SAndroid Build Coastguard Worker switch (mode) {
118*d9f75844SAndroid Build Coastguard Worker case libyuv::kRotate0:
119*d9f75844SAndroid Build Coastguard Worker // copy frame
120*d9f75844SAndroid Build Coastguard Worker libyuv::CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
121*d9f75844SAndroid Build Coastguard Worker height);
122*d9f75844SAndroid Build Coastguard Worker libyuv::CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
123*d9f75844SAndroid Build Coastguard Worker height);
124*d9f75844SAndroid Build Coastguard Worker libyuv::CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
125*d9f75844SAndroid Build Coastguard Worker height);
126*d9f75844SAndroid Build Coastguard Worker return 0;
127*d9f75844SAndroid Build Coastguard Worker case libyuv::kRotate90:
128*d9f75844SAndroid Build Coastguard Worker // We need to rotate and rescale, we use plane Y as temporal storage.
129*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane90_16(src_u, src_stride_u, dst_y, height, halfwidth,
130*d9f75844SAndroid Build Coastguard Worker height);
131*d9f75844SAndroid Build Coastguard Worker libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_u, halfheight,
132*d9f75844SAndroid Build Coastguard Worker halfheight, width, libyuv::kFilterBilinear);
133*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane90_16(src_v, src_stride_v, dst_y, height, halfwidth,
134*d9f75844SAndroid Build Coastguard Worker height);
135*d9f75844SAndroid Build Coastguard Worker libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_v, halfheight,
136*d9f75844SAndroid Build Coastguard Worker halfheight, width, libyuv::kFilterLinear);
137*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
138*d9f75844SAndroid Build Coastguard Worker height);
139*d9f75844SAndroid Build Coastguard Worker return 0;
140*d9f75844SAndroid Build Coastguard Worker case libyuv::kRotate270:
141*d9f75844SAndroid Build Coastguard Worker // We need to rotate and rescale, we use plane Y as temporal storage.
142*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane270_16(src_u, src_stride_u, dst_y, height, halfwidth,
143*d9f75844SAndroid Build Coastguard Worker height);
144*d9f75844SAndroid Build Coastguard Worker libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_u, halfheight,
145*d9f75844SAndroid Build Coastguard Worker halfheight, width, libyuv::kFilterBilinear);
146*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane270_16(src_v, src_stride_v, dst_y, height, halfwidth,
147*d9f75844SAndroid Build Coastguard Worker height);
148*d9f75844SAndroid Build Coastguard Worker libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_v, halfheight,
149*d9f75844SAndroid Build Coastguard Worker halfheight, width, libyuv::kFilterLinear);
150*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
151*d9f75844SAndroid Build Coastguard Worker height);
152*d9f75844SAndroid Build Coastguard Worker
153*d9f75844SAndroid Build Coastguard Worker return 0;
154*d9f75844SAndroid Build Coastguard Worker case libyuv::kRotate180:
155*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
156*d9f75844SAndroid Build Coastguard Worker height);
157*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u,
158*d9f75844SAndroid Build Coastguard Worker halfwidth, height);
159*d9f75844SAndroid Build Coastguard Worker webrtcRotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v,
160*d9f75844SAndroid Build Coastguard Worker halfwidth, height);
161*d9f75844SAndroid Build Coastguard Worker return 0;
162*d9f75844SAndroid Build Coastguard Worker default:
163*d9f75844SAndroid Build Coastguard Worker break;
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker return -1;
166*d9f75844SAndroid Build Coastguard Worker }
167*d9f75844SAndroid Build Coastguard Worker
168*d9f75844SAndroid Build Coastguard Worker } // namespace
169*d9f75844SAndroid Build Coastguard Worker
I210Buffer(int width,int height,int stride_y,int stride_u,int stride_v)170*d9f75844SAndroid Build Coastguard Worker I210Buffer::I210Buffer(int width,
171*d9f75844SAndroid Build Coastguard Worker int height,
172*d9f75844SAndroid Build Coastguard Worker int stride_y,
173*d9f75844SAndroid Build Coastguard Worker int stride_u,
174*d9f75844SAndroid Build Coastguard Worker int stride_v)
175*d9f75844SAndroid Build Coastguard Worker : width_(width),
176*d9f75844SAndroid Build Coastguard Worker height_(height),
177*d9f75844SAndroid Build Coastguard Worker stride_y_(stride_y),
178*d9f75844SAndroid Build Coastguard Worker stride_u_(stride_u),
179*d9f75844SAndroid Build Coastguard Worker stride_v_(stride_v),
180*d9f75844SAndroid Build Coastguard Worker data_(static_cast<uint16_t*>(
181*d9f75844SAndroid Build Coastguard Worker AlignedMalloc(I210DataSize(height, stride_y, stride_u, stride_v),
182*d9f75844SAndroid Build Coastguard Worker kBufferAlignment))) {
183*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(width, 0);
184*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(height, 0);
185*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(stride_y, width);
186*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(stride_u, (width + 1) / 2);
187*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(stride_v, (width + 1) / 2);
188*d9f75844SAndroid Build Coastguard Worker }
189*d9f75844SAndroid Build Coastguard Worker
~I210Buffer()190*d9f75844SAndroid Build Coastguard Worker I210Buffer::~I210Buffer() {}
191*d9f75844SAndroid Build Coastguard Worker
192*d9f75844SAndroid Build Coastguard Worker // static
Create(int width,int height)193*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> I210Buffer::Create(int width, int height) {
194*d9f75844SAndroid Build Coastguard Worker return rtc::make_ref_counted<I210Buffer>(width, height, width,
195*d9f75844SAndroid Build Coastguard Worker (width + 1) / 2, (width + 1) / 2);
196*d9f75844SAndroid Build Coastguard Worker }
197*d9f75844SAndroid Build Coastguard Worker
198*d9f75844SAndroid Build Coastguard Worker // static
Copy(const I210BufferInterface & source)199*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> I210Buffer::Copy(
200*d9f75844SAndroid Build Coastguard Worker const I210BufferInterface& source) {
201*d9f75844SAndroid Build Coastguard Worker const int width = source.width();
202*d9f75844SAndroid Build Coastguard Worker const int height = source.height();
203*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> buffer = Create(width, height);
204*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(
205*d9f75844SAndroid Build Coastguard Worker 0, libyuv::I210Copy(
206*d9f75844SAndroid Build Coastguard Worker source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
207*d9f75844SAndroid Build Coastguard Worker source.DataV(), source.StrideV(), buffer->MutableDataY(),
208*d9f75844SAndroid Build Coastguard Worker buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
209*d9f75844SAndroid Build Coastguard Worker buffer->MutableDataV(), buffer->StrideV(), width, height));
210*d9f75844SAndroid Build Coastguard Worker return buffer;
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker
213*d9f75844SAndroid Build Coastguard Worker // static
Copy(const I420BufferInterface & source)214*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> I210Buffer::Copy(
215*d9f75844SAndroid Build Coastguard Worker const I420BufferInterface& source) {
216*d9f75844SAndroid Build Coastguard Worker const int width = source.width();
217*d9f75844SAndroid Build Coastguard Worker const int height = source.height();
218*d9f75844SAndroid Build Coastguard Worker auto i422buffer = I422Buffer::Copy(source);
219*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> buffer = Create(width, height);
220*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(0, libyuv::I422ToI210(i422buffer->DataY(), i422buffer->StrideY(),
221*d9f75844SAndroid Build Coastguard Worker i422buffer->DataU(), i422buffer->StrideU(),
222*d9f75844SAndroid Build Coastguard Worker i422buffer->DataV(), i422buffer->StrideV(),
223*d9f75844SAndroid Build Coastguard Worker buffer->MutableDataY(), buffer->StrideY(),
224*d9f75844SAndroid Build Coastguard Worker buffer->MutableDataU(), buffer->StrideU(),
225*d9f75844SAndroid Build Coastguard Worker buffer->MutableDataV(), buffer->StrideV(),
226*d9f75844SAndroid Build Coastguard Worker width, height));
227*d9f75844SAndroid Build Coastguard Worker return buffer;
228*d9f75844SAndroid Build Coastguard Worker }
229*d9f75844SAndroid Build Coastguard Worker
230*d9f75844SAndroid Build Coastguard Worker // static
Rotate(const I210BufferInterface & src,VideoRotation rotation)231*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I210Buffer> I210Buffer::Rotate(
232*d9f75844SAndroid Build Coastguard Worker const I210BufferInterface& src,
233*d9f75844SAndroid Build Coastguard Worker VideoRotation rotation) {
234*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(src.DataY());
235*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(src.DataU());
236*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(src.DataV());
237*d9f75844SAndroid Build Coastguard Worker
238*d9f75844SAndroid Build Coastguard Worker int rotated_width = src.width();
239*d9f75844SAndroid Build Coastguard Worker int rotated_height = src.height();
240*d9f75844SAndroid Build Coastguard Worker if (rotation == webrtc::kVideoRotation_90 ||
241*d9f75844SAndroid Build Coastguard Worker rotation == webrtc::kVideoRotation_270) {
242*d9f75844SAndroid Build Coastguard Worker std::swap(rotated_width, rotated_height);
243*d9f75844SAndroid Build Coastguard Worker }
244*d9f75844SAndroid Build Coastguard Worker
245*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::I210Buffer> buffer =
246*d9f75844SAndroid Build Coastguard Worker I210Buffer::Create(rotated_width, rotated_height);
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(0,
249*d9f75844SAndroid Build Coastguard Worker webrtcI210Rotate(
250*d9f75844SAndroid Build Coastguard Worker src.DataY(), src.StrideY(), src.DataU(), src.StrideU(),
251*d9f75844SAndroid Build Coastguard Worker src.DataV(), src.StrideV(), buffer->MutableDataY(),
252*d9f75844SAndroid Build Coastguard Worker buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
253*d9f75844SAndroid Build Coastguard Worker buffer->MutableDataV(), buffer->StrideV(), src.width(),
254*d9f75844SAndroid Build Coastguard Worker src.height(), static_cast<libyuv::RotationMode>(rotation)));
255*d9f75844SAndroid Build Coastguard Worker
256*d9f75844SAndroid Build Coastguard Worker return buffer;
257*d9f75844SAndroid Build Coastguard Worker }
258*d9f75844SAndroid Build Coastguard Worker
ToI420()259*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I420BufferInterface> I210Buffer::ToI420() {
260*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<I420Buffer> i420_buffer =
261*d9f75844SAndroid Build Coastguard Worker I420Buffer::Create(width(), height());
262*d9f75844SAndroid Build Coastguard Worker libyuv::I210ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
263*d9f75844SAndroid Build Coastguard Worker i420_buffer->MutableDataY(), i420_buffer->StrideY(),
264*d9f75844SAndroid Build Coastguard Worker i420_buffer->MutableDataU(), i420_buffer->StrideU(),
265*d9f75844SAndroid Build Coastguard Worker i420_buffer->MutableDataV(), i420_buffer->StrideV(),
266*d9f75844SAndroid Build Coastguard Worker width(), height());
267*d9f75844SAndroid Build Coastguard Worker return i420_buffer;
268*d9f75844SAndroid Build Coastguard Worker }
269*d9f75844SAndroid Build Coastguard Worker
width() const270*d9f75844SAndroid Build Coastguard Worker int I210Buffer::width() const {
271*d9f75844SAndroid Build Coastguard Worker return width_;
272*d9f75844SAndroid Build Coastguard Worker }
273*d9f75844SAndroid Build Coastguard Worker
height() const274*d9f75844SAndroid Build Coastguard Worker int I210Buffer::height() const {
275*d9f75844SAndroid Build Coastguard Worker return height_;
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker
DataY() const278*d9f75844SAndroid Build Coastguard Worker const uint16_t* I210Buffer::DataY() const {
279*d9f75844SAndroid Build Coastguard Worker return data_.get();
280*d9f75844SAndroid Build Coastguard Worker }
DataU() const281*d9f75844SAndroid Build Coastguard Worker const uint16_t* I210Buffer::DataU() const {
282*d9f75844SAndroid Build Coastguard Worker return data_.get() + stride_y_ * height_;
283*d9f75844SAndroid Build Coastguard Worker }
DataV() const284*d9f75844SAndroid Build Coastguard Worker const uint16_t* I210Buffer::DataV() const {
285*d9f75844SAndroid Build Coastguard Worker return data_.get() + stride_y_ * height_ + stride_u_ * height_;
286*d9f75844SAndroid Build Coastguard Worker }
287*d9f75844SAndroid Build Coastguard Worker
StrideY() const288*d9f75844SAndroid Build Coastguard Worker int I210Buffer::StrideY() const {
289*d9f75844SAndroid Build Coastguard Worker return stride_y_;
290*d9f75844SAndroid Build Coastguard Worker }
StrideU() const291*d9f75844SAndroid Build Coastguard Worker int I210Buffer::StrideU() const {
292*d9f75844SAndroid Build Coastguard Worker return stride_u_;
293*d9f75844SAndroid Build Coastguard Worker }
StrideV() const294*d9f75844SAndroid Build Coastguard Worker int I210Buffer::StrideV() const {
295*d9f75844SAndroid Build Coastguard Worker return stride_v_;
296*d9f75844SAndroid Build Coastguard Worker }
297*d9f75844SAndroid Build Coastguard Worker
MutableDataY()298*d9f75844SAndroid Build Coastguard Worker uint16_t* I210Buffer::MutableDataY() {
299*d9f75844SAndroid Build Coastguard Worker return const_cast<uint16_t*>(DataY());
300*d9f75844SAndroid Build Coastguard Worker }
MutableDataU()301*d9f75844SAndroid Build Coastguard Worker uint16_t* I210Buffer::MutableDataU() {
302*d9f75844SAndroid Build Coastguard Worker return const_cast<uint16_t*>(DataU());
303*d9f75844SAndroid Build Coastguard Worker }
MutableDataV()304*d9f75844SAndroid Build Coastguard Worker uint16_t* I210Buffer::MutableDataV() {
305*d9f75844SAndroid Build Coastguard Worker return const_cast<uint16_t*>(DataV());
306*d9f75844SAndroid Build Coastguard Worker }
307*d9f75844SAndroid Build Coastguard Worker
CropAndScaleFrom(const I210BufferInterface & src,int offset_x,int offset_y,int crop_width,int crop_height)308*d9f75844SAndroid Build Coastguard Worker void I210Buffer::CropAndScaleFrom(const I210BufferInterface& src,
309*d9f75844SAndroid Build Coastguard Worker int offset_x,
310*d9f75844SAndroid Build Coastguard Worker int offset_y,
311*d9f75844SAndroid Build Coastguard Worker int crop_width,
312*d9f75844SAndroid Build Coastguard Worker int crop_height) {
313*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_LE(crop_width, src.width());
314*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_LE(crop_height, src.height());
315*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_LE(crop_width + offset_x, src.width());
316*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_LE(crop_height + offset_y, src.height());
317*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_GE(offset_x, 0);
318*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_GE(offset_y, 0);
319*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_GE(crop_width, 0);
320*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_GE(crop_height, 0);
321*d9f75844SAndroid Build Coastguard Worker
322*d9f75844SAndroid Build Coastguard Worker // Make sure offset is even so that u/v plane becomes aligned.
323*d9f75844SAndroid Build Coastguard Worker const int uv_offset_x = offset_x / 2;
324*d9f75844SAndroid Build Coastguard Worker const int uv_offset_y = offset_y;
325*d9f75844SAndroid Build Coastguard Worker offset_x = uv_offset_x * 2;
326*d9f75844SAndroid Build Coastguard Worker
327*d9f75844SAndroid Build Coastguard Worker const uint16_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
328*d9f75844SAndroid Build Coastguard Worker const uint16_t* u_plane =
329*d9f75844SAndroid Build Coastguard Worker src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x;
330*d9f75844SAndroid Build Coastguard Worker const uint16_t* v_plane =
331*d9f75844SAndroid Build Coastguard Worker src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x;
332*d9f75844SAndroid Build Coastguard Worker int res = libyuv::I422Scale_16(
333*d9f75844SAndroid Build Coastguard Worker y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane, src.StrideV(),
334*d9f75844SAndroid Build Coastguard Worker crop_width, crop_height, MutableDataY(), StrideY(), MutableDataU(),
335*d9f75844SAndroid Build Coastguard Worker StrideU(), MutableDataV(), StrideV(), width(), height(),
336*d9f75844SAndroid Build Coastguard Worker libyuv::kFilterBox);
337*d9f75844SAndroid Build Coastguard Worker
338*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(res, 0);
339*d9f75844SAndroid Build Coastguard Worker }
340*d9f75844SAndroid Build Coastguard Worker
ScaleFrom(const I210BufferInterface & src)341*d9f75844SAndroid Build Coastguard Worker void I210Buffer::ScaleFrom(const I210BufferInterface& src) {
342*d9f75844SAndroid Build Coastguard Worker CropAndScaleFrom(src, 0, 0, src.width(), src.height());
343*d9f75844SAndroid Build Coastguard Worker }
344*d9f75844SAndroid Build Coastguard Worker
345*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
346