Use libyuv rotate methods

Bug: webrtc:13826
Change-Id: I10a3b291a66eae1b867dd2fa1a1781c235feef33
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/290703
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39060}
This commit is contained in:
Sergio Garcia Murillo 2023-01-09 16:08:20 +01:00 committed by WebRTC LUCI CQ
parent 143c3b2b4c
commit bfc26c65e6
3 changed files with 59 additions and 211 deletions

View File

@ -66,12 +66,13 @@ rtc::scoped_refptr<I010Buffer> I010Buffer::Copy(
const int width = source.width();
const int height = source.height();
rtc::scoped_refptr<I010Buffer> buffer = Create(width, height);
RTC_CHECK_EQ(
0, libyuv::I010Copy(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height));
int res = libyuv::I010Copy(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height);
RTC_DCHECK_EQ(res, 0);
return buffer;
}
@ -81,12 +82,13 @@ rtc::scoped_refptr<I010Buffer> I010Buffer::Copy(
const int width = source.width();
const int height = source.height();
rtc::scoped_refptr<I010Buffer> buffer = Create(width, height);
RTC_CHECK_EQ(
0, libyuv::I420ToI010(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height));
int res = libyuv::I420ToI010(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height);
RTC_DCHECK_EQ(res, 0);
return buffer;
}
@ -109,52 +111,28 @@ rtc::scoped_refptr<I010Buffer> I010Buffer::Rotate(
rtc::scoped_refptr<webrtc::I010Buffer> buffer =
Create(rotated_width, rotated_height);
// TODO(emircan): Remove this when there is libyuv::I010Rotate().
for (int x = 0; x < src.width(); x++) {
for (int y = 0; y < src.height(); y++) {
int dest_x = x;
int dest_y = y;
switch (rotation) {
// This case is covered by the early return.
case webrtc::kVideoRotation_0:
RTC_DCHECK_NOTREACHED();
break;
case webrtc::kVideoRotation_90:
dest_x = src.height() - y - 1;
dest_y = x;
break;
case webrtc::kVideoRotation_180:
dest_x = src.width() - x - 1;
dest_y = src.height() - y - 1;
break;
case webrtc::kVideoRotation_270:
dest_x = y;
dest_y = src.width() - x - 1;
break;
}
buffer->MutableDataY()[dest_x + buffer->StrideY() * dest_y] =
src.DataY()[x + src.StrideY() * y];
dest_x /= 2;
dest_y /= 2;
int src_x = x / 2;
int src_y = y / 2;
buffer->MutableDataU()[dest_x + buffer->StrideU() * dest_y] =
src.DataU()[src_x + src.StrideU() * src_y];
buffer->MutableDataV()[dest_x + buffer->StrideV() * dest_y] =
src.DataV()[src_x + src.StrideV() * src_y];
}
}
int res = libyuv::I010Rotate(
src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), src.DataV(),
src.StrideV(), buffer->MutableDataY(), buffer->StrideY(),
buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(),
buffer->StrideV(), src.width(), src.height(),
static_cast<libyuv::RotationMode>(rotation));
RTC_DCHECK_EQ(res, 0);
return buffer;
}
rtc::scoped_refptr<I420BufferInterface> I010Buffer::ToI420() {
rtc::scoped_refptr<I420Buffer> i420_buffer =
I420Buffer::Create(width(), height());
libyuv::I010ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
i420_buffer->MutableDataY(), i420_buffer->StrideY(),
i420_buffer->MutableDataU(), i420_buffer->StrideU(),
i420_buffer->MutableDataV(), i420_buffer->StrideV(),
width(), height());
int res = libyuv::I010ToI420(
DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
i420_buffer->MutableDataY(), i420_buffer->StrideY(),
i420_buffer->MutableDataU(), i420_buffer->StrideU(),
i420_buffer->MutableDataV(), i420_buffer->StrideV(), width(), height());
RTC_DCHECK_EQ(res, 0);
return i420_buffer;
}

View File

@ -31,140 +31,6 @@ int I210DataSize(int height, int stride_y, int stride_u, int stride_v) {
(stride_y * height + stride_u * height + stride_v * height);
}
void webrtcRotatePlane90_16(const uint16_t* src,
int src_stride,
uint16_t* dst,
int dst_stride,
int width,
int height) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dest_x = height - y - 1;
int dest_y = x;
dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
}
}
}
void webrtcRotatePlane180_16(const uint16_t* src,
int src_stride,
uint16_t* dst,
int dst_stride,
int width,
int height) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dest_x = width - x - 1;
int dest_y = height - y - 1;
dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
}
}
}
void webrtcRotatePlane270_16(const uint16_t* src,
int src_stride,
uint16_t* dst,
int dst_stride,
int width,
int height) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dest_x = y;
int dest_y = width - x - 1;
dst[dest_x + dst_stride * dest_y] = src[x + src_stride * y];
}
}
}
// TODO(sergio.garcia.murillo@gmail.com): Remove as soon it is available in
// libyuv. Due to the rotate&scale required, this function may not be merged in
// to libyuv inmediatelly.
// https://bugs.chromium.org/p/libyuv/issues/detail?id=926
// This method assumes continuous allocation of the y-plane, possibly clobbering
// any padding between pixel rows.
int 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) {
int halfwidth = (width + 1) >> 1;
int halfheight = (height + 1) >> 1;
if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
!dst_u || !dst_v || dst_stride_y < 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_stride_y;
src_u = src_u + (height - 1) * src_stride_u;
src_v = src_v + (height - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
switch (mode) {
case libyuv::kRotate0:
// copy frame
libyuv::CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
height);
libyuv::CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
height);
libyuv::CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
height);
return 0;
case libyuv::kRotate90:
// We need to rotate and rescale, we use plane Y as temporal storage.
webrtcRotatePlane90_16(src_u, src_stride_u, dst_y, height, halfwidth,
height);
libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_u, halfheight,
halfheight, width, libyuv::kFilterBilinear);
webrtcRotatePlane90_16(src_v, src_stride_v, dst_y, height, halfwidth,
height);
libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_v, halfheight,
halfheight, width, libyuv::kFilterLinear);
webrtcRotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
height);
return 0;
case libyuv::kRotate270:
// We need to rotate and rescale, we use plane Y as temporal storage.
webrtcRotatePlane270_16(src_u, src_stride_u, dst_y, height, halfwidth,
height);
libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_u, halfheight,
halfheight, width, libyuv::kFilterBilinear);
webrtcRotatePlane270_16(src_v, src_stride_v, dst_y, height, halfwidth,
height);
libyuv::ScalePlane_16(dst_y, height, height, halfwidth, dst_v, halfheight,
halfheight, width, libyuv::kFilterLinear);
webrtcRotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
height);
return 0;
case libyuv::kRotate180:
webrtcRotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
height);
webrtcRotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u,
halfwidth, height);
webrtcRotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v,
halfwidth, height);
return 0;
default:
break;
}
return -1;
}
} // namespace
I210Buffer::I210Buffer(int width,
@ -246,7 +112,7 @@ rtc::scoped_refptr<I210Buffer> I210Buffer::Rotate(
I210Buffer::Create(rotated_width, rotated_height);
RTC_CHECK_EQ(0,
webrtcI210Rotate(
libyuv::I210Rotate(
src.DataY(), src.StrideY(), src.DataU(), src.StrideU(),
src.DataV(), src.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),

View File

@ -87,12 +87,13 @@ rtc::scoped_refptr<I422Buffer> I422Buffer::Copy(
const int width = source.width();
const int height = source.height();
rtc::scoped_refptr<I422Buffer> buffer = Create(width, height);
RTC_CHECK_EQ(
0, libyuv::I420ToI422(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height));
int res = libyuv::I420ToI422(
source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
source.DataV(), source.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), width, height);
RTC_DCHECK_EQ(res, 0);
return buffer;
}
@ -107,11 +108,13 @@ rtc::scoped_refptr<I422Buffer> I422Buffer::Copy(int width,
int stride_v) {
// Note: May use different strides than the input data.
rtc::scoped_refptr<I422Buffer> buffer = Create(width, height);
RTC_CHECK_EQ(0, libyuv::I422Copy(data_y, stride_y, data_u, stride_u, data_v,
stride_v, buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(),
buffer->StrideU(), buffer->MutableDataV(),
buffer->StrideV(), width, height));
int res = libyuv::I422Copy(data_y, stride_y, data_u, stride_u, data_v,
stride_v, buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(),
buffer->StrideU(), buffer->MutableDataV(),
buffer->StrideV(), width, height);
RTC_DCHECK_EQ(res, 0);
return buffer;
}
@ -133,13 +136,13 @@ rtc::scoped_refptr<I422Buffer> I422Buffer::Rotate(
rtc::scoped_refptr<webrtc::I422Buffer> buffer =
I422Buffer::Create(rotated_width, rotated_height);
RTC_CHECK_EQ(0,
libyuv::I422Rotate(
src.DataY(), src.StrideY(), src.DataU(), src.StrideU(),
src.DataV(), src.StrideV(), buffer->MutableDataY(),
buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
buffer->MutableDataV(), buffer->StrideV(), src.width(),
src.height(), static_cast<libyuv::RotationMode>(rotation)));
int res = libyuv::I422Rotate(
src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), src.DataV(),
src.StrideV(), buffer->MutableDataY(), buffer->StrideY(),
buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(),
buffer->StrideV(), src.width(), src.height(),
static_cast<libyuv::RotationMode>(rotation));
RTC_DCHECK_EQ(res, 0);
return buffer;
}
@ -147,11 +150,13 @@ rtc::scoped_refptr<I422Buffer> I422Buffer::Rotate(
rtc::scoped_refptr<I420BufferInterface> I422Buffer::ToI420() {
rtc::scoped_refptr<I420Buffer> i420_buffer =
I420Buffer::Create(width(), height());
libyuv::I422ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
i420_buffer->MutableDataY(), i420_buffer->StrideY(),
i420_buffer->MutableDataU(), i420_buffer->StrideU(),
i420_buffer->MutableDataV(), i420_buffer->StrideV(),
width(), height());
int res = libyuv::I422ToI420(
DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
i420_buffer->MutableDataY(), i420_buffer->StrideY(),
i420_buffer->MutableDataU(), i420_buffer->StrideU(),
i420_buffer->MutableDataV(), i420_buffer->StrideV(), width(), height());
RTC_DCHECK_EQ(res, 0);
return i420_buffer;
}
@ -226,7 +231,6 @@ void I422Buffer::CropAndScaleFrom(const I422BufferInterface& src,
src.StrideV(), crop_width, crop_height, MutableDataY(),
StrideY(), MutableDataU(), StrideU(), MutableDataV(),
StrideV(), width(), height(), libyuv::kFilterBox);
RTC_DCHECK_EQ(res, 0);
}