Add P010ToNV12 to convert 10 bit biplanar to 8 bit biplanar

- P010 and NV12 have the same layout: Full size Y plane and half size UV plane.
  P010 and NV12 are 4:2:0 subsampling
- P010 uses upper 10 bits of 16 bit elements
- NV12 uses 8 bit elements
- The Convert16To8 used internally will discard the low 2 bits.
- UV order is the same - U first in memory, followed by V, interleaved
- UV plane is be rounded up in size to allow odd size Y to have UV values
- Similar code could be used to convert P210ToNV16, P410ToNV24, with the size
  of the UV plane affected by subsampling 4:2:2 and 4:4:4 variants.

Bug: b/357439226
Change-Id: I5d6ec84d97d0e0cc4008eeb18a929ea28570d6d9
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/5761958
Reviewed-by: Wan-Teh Chang <wtc@google.com>
This commit is contained in:
Frank Barchard 2024-08-04 16:46:32 -07:00
parent e462de319c
commit 32ccd53bb3
5 changed files with 81 additions and 4 deletions

View File

@ -1,6 +1,6 @@
Name: libyuv
URL: https://chromium.googlesource.com/libyuv/libyuv/
Version: 1892
Version: 1893
License: BSD
License File: LICENSE
Shipped: yes

View File

@ -418,6 +418,20 @@ int I412ToI420(const uint16_t* src_y,
int width,
int height);
// Convert 10 bit P010 to 8 bit NV12.
// dst_y can be NULL
LIBYUV_API
int P010ToNV12(const uint16_t* src_y,
int src_stride_y,
const uint16_t* src_uv,
int src_stride_uv,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_uv,
int dst_stride_uv,
int width,
int height);
#define I412ToI012 I410ToI010
#define H410ToH010 I410ToI010
#define H412ToH012 I410ToI010

View File

@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1892
#define LIBYUV_VERSION 1893
#endif // INCLUDE_LIBYUV_VERSION_H_

View File

@ -202,8 +202,10 @@ static int Planar16bitTo8bit(const uint16_t* src_y,
}
// Convert Y plane.
Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
height);
if (dst_y) {
Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
height);
}
// Convert UV planes.
Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
uv_height);
@ -4147,6 +4149,66 @@ int Android420ToI420(const uint8_t* src_y,
dst_stride_v, width, height, kRotate0);
}
// depth is source bits measured from lsb; For msb use 16
static int Biplanar16bitTo8bit(const uint16_t* src_y,
int src_stride_y,
const uint16_t* src_uv,
int src_stride_uv,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_uv,
int dst_stride_uv,
int width,
int height,
int subsample_x,
int subsample_y,
int depth) {
int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
int scale = 1 << (24 - depth);
if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
uv_height = -uv_height;
src_y = src_y + (height - 1) * src_stride_y;
src_uv = src_uv + (uv_height - 1) * src_stride_uv;
src_stride_y = -src_stride_y;
src_stride_uv = -src_stride_uv;
}
// Convert Y plane.
if (dst_y) {
Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
height);
}
// Convert UV planes.
Convert16To8Plane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, scale,
uv_width * 2, uv_height);
return 0;
}
// Convert 10 bit P010 to 8 bit NV12.
// Depth set to 16 because P010 uses 10 msb and this function keeps the upper 8
// bits of the specified number of bits.
LIBYUV_API
int P010ToNV12(const uint16_t* src_y,
int src_stride_y,
const uint16_t* src_uv,
int src_stride_uv,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_uv,
int dst_stride_uv,
int width,
int height) {
return Biplanar16bitTo8bit(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
dst_stride_y, dst_uv, dst_stride_uv, width, height,
1, 1, 16);
}
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv

View File

@ -592,6 +592,7 @@ TESTBPTOBP(P016, uint16_t, 2, 2, 2, P416, uint16_t, 2, 1, 1, 12, 1, 1)
TESTBPTOBP(P216, uint16_t, 2, 2, 1, P416, uint16_t, 2, 1, 1, 12, 1, 1)
TESTBPTOBP(MM21, uint8_t, 1, 2, 2, NV12, uint8_t, 1, 2, 2, 8, 16, 32)
TESTBPTOBP(MT2T, uint8_t, 10 / 8, 2, 2, P010, uint16_t, 2, 2, 2, 10, 16, 32)
TESTBPTOBP(P010, uint16_t, 2, 2, 2, NV12, uint8_t, 1, 2, 2, 8, 1, 1)
#define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
W1280, N, NEG, OFF) \