mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2025-12-07 17:26:49 +08:00
Add tentative I422Rotate.
When doing 90 or 270 degrees rotation we need to do a rotate&scale of the UV planes, as there are no helper optimized functions to do this, we use the Y plane as temporal memory and perform each of the transforms independently: First U plane is rotated, putting the result in the Y plane. After the rotation, the output has double the samples horizontally and half the samples vertically, so it is scaled into the final U plane. Same process is done with the V plane. Last the Y plane that can be just rotated without scaling. It would be great to have an optimized version for this, but maybe this is helpfull for triggering the discussions. Bug: libyuv:926 Change-Id: I188af103c4d0e3f9522021b4bf2b63c9d5de8b93 Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3568424 Reviewed-by: Frank Barchard <fbarchard@chromium.org> Commit-Queue: Frank Barchard <fbarchard@chromium.org>
This commit is contained in:
parent
4589081cea
commit
a77d615e10
@ -49,6 +49,24 @@ int I420Rotate(const uint8_t* src_y,
|
||||
int height,
|
||||
enum RotationMode mode);
|
||||
|
||||
// Rotate I422 frame.
|
||||
LIBYUV_API
|
||||
int I422Rotate(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height,
|
||||
enum libyuv::RotationMode mode);
|
||||
|
||||
// Rotate I444 frame.
|
||||
LIBYUV_API
|
||||
int I444Rotate(const uint8_t* src_y,
|
||||
|
||||
@ -11,6 +11,6 @@
|
||||
#ifndef INCLUDE_LIBYUV_VERSION_H_
|
||||
#define INCLUDE_LIBYUV_VERSION_H_
|
||||
|
||||
#define LIBYUV_VERSION 1816
|
||||
#define LIBYUV_VERSION 1817
|
||||
|
||||
#endif // INCLUDE_LIBYUV_VERSION_H_
|
||||
|
||||
@ -544,6 +544,90 @@ int I420Rotate(const uint8_t* src_y,
|
||||
return -1;
|
||||
}
|
||||
|
||||
LIBYUV_API
|
||||
int I422Rotate(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_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) {
|
||||
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(src_y, src_stride_y, dst_y, dst_stride_y, width,
|
||||
height);
|
||||
libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
|
||||
height);
|
||||
libyuv::CopyPlane(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.
|
||||
libyuv::RotatePlane90(src_u, src_stride_u, dst_y, height, halfwidth,
|
||||
height);
|
||||
libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight,
|
||||
halfheight, width, libyuv::kFilterBilinear);
|
||||
libyuv::RotatePlane90(src_v, src_stride_v, dst_y, height, halfwidth,
|
||||
height);
|
||||
libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight,
|
||||
halfheight, width, libyuv::kFilterLinear);
|
||||
libyuv::RotatePlane90(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.
|
||||
libyuv::RotatePlane270(src_u, src_stride_u, dst_y, height, halfwidth,
|
||||
height);
|
||||
libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight,
|
||||
halfheight, width, libyuv::kFilterBilinear);
|
||||
libyuv::RotatePlane270(src_v, src_stride_v, dst_y, height, halfwidth,
|
||||
height);
|
||||
libyuv::ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight,
|
||||
halfheight, width, libyuv::kFilterLinear);
|
||||
libyuv::RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width,
|
||||
height);
|
||||
|
||||
return 0;
|
||||
case libyuv::kRotate180:
|
||||
libyuv::RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width,
|
||||
height);
|
||||
libyuv::RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u,
|
||||
halfwidth, height);
|
||||
libyuv::RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v,
|
||||
halfwidth, height);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
LIBYUV_API
|
||||
int I444Rotate(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
|
||||
@ -137,6 +137,94 @@ TEST_F(LibYUVRotateTest, DISABLED_I420Rotate270_Odd) {
|
||||
benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
static void I422TestRotate(int src_width,
|
||||
int src_height,
|
||||
int dst_width,
|
||||
int dst_height,
|
||||
libyuv::RotationMode mode,
|
||||
int benchmark_iterations,
|
||||
int disable_cpu_flags,
|
||||
int benchmark_cpu_info) {
|
||||
if (src_width < 1) {
|
||||
src_width = 1;
|
||||
}
|
||||
if (src_height == 0) {
|
||||
src_height = 1;
|
||||
}
|
||||
if (dst_width < 1) {
|
||||
dst_width = 1;
|
||||
}
|
||||
if (dst_height < 1) {
|
||||
dst_height = 1;
|
||||
}
|
||||
int src_i422_y_size = src_width * Abs(src_height);
|
||||
int src_i422_uv_size = ((src_width + 1) / 2) * Abs(src_height);
|
||||
int src_i422_size = src_i422_y_size + src_i422_uv_size * 2;
|
||||
align_buffer_page_end(src_i422, src_i422_size);
|
||||
for (int i = 0; i < src_i422_size; ++i) {
|
||||
src_i422[i] = fastrand() & 0xff;
|
||||
}
|
||||
|
||||
int dst_i422_y_size = dst_width * dst_height;
|
||||
int dst_i422_uv_size = ((dst_width + 1) / 2) * dst_height;
|
||||
int dst_i422_size = dst_i422_y_size + dst_i422_uv_size * 2;
|
||||
align_buffer_page_end(dst_i422_c, dst_i422_size);
|
||||
align_buffer_page_end(dst_i422_opt, dst_i422_size);
|
||||
memset(dst_i422_c, 2, dst_i422_size);
|
||||
memset(dst_i422_opt, 3, dst_i422_size);
|
||||
|
||||
MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
|
||||
I422Rotate(src_i422, src_width, src_i422 + src_i422_y_size,
|
||||
(src_width + 1) / 2, src_i422 + src_i422_y_size + src_i422_uv_size,
|
||||
(src_width + 1) / 2, dst_i422_c, dst_width,
|
||||
dst_i422_c + dst_i422_y_size, (dst_width + 1) / 2,
|
||||
dst_i422_c + dst_i422_y_size + dst_i422_uv_size,
|
||||
(dst_width + 1) / 2, src_width, src_height, mode);
|
||||
|
||||
MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
|
||||
for (int i = 0; i < benchmark_iterations; ++i) {
|
||||
I422Rotate(
|
||||
src_i422, src_width, src_i422 + src_i422_y_size, (src_width + 1) / 2,
|
||||
src_i422 + src_i422_y_size + src_i422_uv_size, (src_width + 1) / 2,
|
||||
dst_i422_opt, dst_width, dst_i422_opt + dst_i422_y_size,
|
||||
(dst_width + 1) / 2, dst_i422_opt + dst_i422_y_size + dst_i422_uv_size,
|
||||
(dst_width + 1) / 2, src_width, src_height, mode);
|
||||
}
|
||||
|
||||
// Rotation should be exact.
|
||||
for (int i = 0; i < dst_i422_size; ++i) {
|
||||
EXPECT_EQ(dst_i422_c[i], dst_i422_opt[i]);
|
||||
}
|
||||
|
||||
free_aligned_buffer_page_end(dst_i422_c);
|
||||
free_aligned_buffer_page_end(dst_i422_opt);
|
||||
free_aligned_buffer_page_end(src_i422);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVRotateTest, I422Rotate0_Opt) {
|
||||
I422TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
|
||||
benchmark_height_, kRotate0, benchmark_iterations_,
|
||||
disable_cpu_flags_, benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVRotateTest, I422Rotate90_Opt) {
|
||||
I422TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
|
||||
benchmark_width_, kRotate90, benchmark_iterations_,
|
||||
disable_cpu_flags_, benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVRotateTest, I422Rotate180_Opt) {
|
||||
I422TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
|
||||
benchmark_height_, kRotate180, benchmark_iterations_,
|
||||
disable_cpu_flags_, benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVRotateTest, I422Rotate270_Opt) {
|
||||
I422TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
|
||||
benchmark_width_, kRotate270, benchmark_iterations_,
|
||||
disable_cpu_flags_, benchmark_cpu_info_);
|
||||
}
|
||||
|
||||
static void I444TestRotate(int src_width,
|
||||
int src_height,
|
||||
int dst_width,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user