mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-28 18:07:12 +08:00
convert, scale: Add P010/P210/P410 convert paths and NV16/NV24/Px10 scale
P010 and P210 were auxiliary FourCCs and P410 did not exist, so ConvertToI420, ConvertToARGB, and ConvertFromI420 could not consume or produce them. Callers had to pick I010/I210 helpers and pack UV by hand. NV12Scale existed, but NV16/NV24 and P010/P210/P410 had no Scale APIs. Promote P010 and P210 to primary FourCCs, add FOURCC_P410, and add the I4xx/Px10 converters those entry points need: I410ToP410, I412ToP412, P210ToI210, P410ToI410, P010/P210/P410ToI420, I420ToP010/P210/P410, I422ToP210, I444ToP410, and P410ToARGB/AR30Matrix. Add NV16Scale (same path as NV12Scale: ScalePlane + UVScale). Add P010Scale, P210Scale, and P410Scale: 10-bit samples stay in the MSBs, so Y/UV convert to 10-bit LSB, ScalePlane_16, then back to MSB. UVScale_16 cannot general-scale, so UV is split, scaled as planes, and merged. Packed-plane layout, odd-width strides, ConvertTo/From round-trips, and the existing scale factor/size/swap tests cover the new APIs. Bug: 537818862 Change-Id: I1ae5e6cad5e6d83acf1d0df69f94c23688bbe0e8 Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8346569 Reviewed-by: Frank Barchard <fbarchard@google.com> Reviewed-by: richard winterton <rrwinterton@gmail.com>
This commit is contained in:
parent
eae15e5fdd
commit
dab3111c8a
@ -38,7 +38,7 @@ This is how OSX formats map to libyuv
|
|||||||
|
|
||||||
The following is extracted from video_common.h as a complete list of formats supported by libyuv.
|
The following is extracted from video_common.h as a complete list of formats supported by libyuv.
|
||||||
enum FourCC {
|
enum FourCC {
|
||||||
// 12 Primary YUV formats: 5 planar, 4 biplanar, 2 packed.
|
// 15 Primary YUV formats: 6 planar, 7 biplanar, 2 packed.
|
||||||
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
|
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
|
||||||
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
|
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
|
||||||
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
|
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
|
||||||
@ -47,11 +47,13 @@ The following is extracted from video_common.h as a complete list of formats sup
|
|||||||
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
|
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
|
||||||
FOURCC_NV16 = FOURCC('N', 'V', '1', '6'),
|
FOURCC_NV16 = FOURCC('N', 'V', '1', '6'),
|
||||||
FOURCC_NV24 = FOURCC('N', 'V', '2', '4'),
|
FOURCC_NV24 = FOURCC('N', 'V', '2', '4'),
|
||||||
|
FOURCC_P010 = FOURCC('P', '0', '1', '0'),
|
||||||
|
FOURCC_P210 = FOURCC('P', '2', '1', '0'),
|
||||||
|
FOURCC_P410 = FOURCC('P', '4', '1', '0'),
|
||||||
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
|
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
|
||||||
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
|
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
|
||||||
FOURCC_H010 = FOURCC('H', '0', '1', '0'), // unofficial fourcc. 10 bit lsb
|
FOURCC_I010 = FOURCC('I', '0', '1', '0'), // bt.601 10 bit 420
|
||||||
FOURCC_U010 = FOURCC('U', '0', '1', '0'), // bt.2020, unofficial fourcc.
|
FOURCC_I210 = FOURCC('I', '2', '1', '0'), // bt.601 10 bit 422
|
||||||
// 10 bit lsb
|
|
||||||
|
|
||||||
// 1 Secondary YUV format: row biplanar.
|
// 1 Secondary YUV format: row biplanar.
|
||||||
FOURCC_M420 = FOURCC('M', '4', '2', '0'), // deprecated.
|
FOURCC_M420 = FOURCC('M', '4', '2', '0'), // deprecated.
|
||||||
@ -74,18 +76,34 @@ The following is extracted from video_common.h as a complete list of formats sup
|
|||||||
// 1 Primary Compressed YUV format.
|
// 1 Primary Compressed YUV format.
|
||||||
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
|
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
|
||||||
|
|
||||||
// 11 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
|
// 23 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
|
||||||
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
|
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
|
||||||
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
|
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
|
||||||
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
|
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
|
||||||
FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420.
|
FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420.
|
||||||
FOURCC_J420 = FOURCC('J', '4', '2', '0'),
|
FOURCC_J420 =
|
||||||
FOURCC_J400 = FOURCC('J', '4', '0', '0'), // unofficial fourcc
|
FOURCC('J', '4', '2', '0'), // jpeg (bt.601 full), unofficial fourcc
|
||||||
FOURCC_H420 = FOURCC('H', '4', '2', '0'), // unofficial fourcc
|
FOURCC_J422 =
|
||||||
FOURCC_H422 = FOURCC('H', '4', '2', '2'), // unofficial fourcc
|
FOURCC('J', '4', '2', '2'), // jpeg (bt.601 full), unofficial fourcc
|
||||||
|
FOURCC_J444 =
|
||||||
|
FOURCC('J', '4', '4', '4'), // jpeg (bt.601 full), unofficial fourcc
|
||||||
|
FOURCC_J400 =
|
||||||
|
FOURCC('J', '4', '0', '0'), // jpeg (bt.601 full), unofficial fourcc
|
||||||
|
FOURCC_F420 = FOURCC('F', '4', '2', '0'), // bt.709 full, unofficial fourcc
|
||||||
|
FOURCC_F422 = FOURCC('F', '4', '2', '2'), // bt.709 full, unofficial fourcc
|
||||||
|
FOURCC_F444 = FOURCC('F', '4', '4', '4'), // bt.709 full, unofficial fourcc
|
||||||
|
FOURCC_H420 = FOURCC('H', '4', '2', '0'), // bt.709, unofficial fourcc
|
||||||
|
FOURCC_H422 = FOURCC('H', '4', '2', '2'), // bt.709, unofficial fourcc
|
||||||
|
FOURCC_H444 = FOURCC('H', '4', '4', '4'), // bt.709, unofficial fourcc
|
||||||
FOURCC_U420 = FOURCC('U', '4', '2', '0'), // bt.2020, unofficial fourcc
|
FOURCC_U420 = FOURCC('U', '4', '2', '0'), // bt.2020, unofficial fourcc
|
||||||
FOURCC_U422 = FOURCC('U', '4', '2', '2'), // bt.2020, unofficial fourcc
|
FOURCC_U422 = FOURCC('U', '4', '2', '2'), // bt.2020, unofficial fourcc
|
||||||
FOURCC_U444 = FOURCC('U', '4', '4', '4'), // bt.2020, unofficial fourcc
|
FOURCC_U444 = FOURCC('U', '4', '4', '4'), // bt.2020, unofficial fourcc
|
||||||
|
FOURCC_F010 = FOURCC('F', '0', '1', '0'), // bt.709 full range 10 bit 420
|
||||||
|
FOURCC_H010 = FOURCC('H', '0', '1', '0'), // bt.709 10 bit 420
|
||||||
|
FOURCC_U010 = FOURCC('U', '0', '1', '0'), // bt.2020 10 bit 420
|
||||||
|
FOURCC_F210 = FOURCC('F', '2', '1', '0'), // bt.709 full range 10 bit 422
|
||||||
|
FOURCC_H210 = FOURCC('H', '2', '1', '0'), // bt.709 10 bit 422
|
||||||
|
FOURCC_U210 = FOURCC('U', '2', '1', '0'), // bt.2020 10 bit 422
|
||||||
|
|
||||||
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
|
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
|
||||||
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
|
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
|
||||||
@ -108,11 +126,12 @@ The following is extracted from video_common.h as a complete list of formats sup
|
|||||||
|
|
||||||
# Planar YUV
|
# Planar YUV
|
||||||
The following formats contains a full size Y plane followed by 1 or 2
|
The following formats contains a full size Y plane followed by 1 or 2
|
||||||
planes for UV: I420, I422, I444, I400, NV21, NV12, I400
|
planes for UV: I420, I422, I444, I400, NV21, NV12, NV16, NV24,
|
||||||
|
P010, P210, P410
|
||||||
The size (subsampling) of the UV varies.
|
The size (subsampling) of the UV varies.
|
||||||
I420, NV12 and NV21 are half width, half height
|
I420, NV12, NV21 and P010 are half width, half height
|
||||||
I422, NV16 and NV61 are half width, full height
|
I422, NV16, NV61 and P210 are half width, full height
|
||||||
I444, NV24 and NV42 are full width, full height
|
I444, NV24, NV42 and P410 are full width, full height
|
||||||
I400 and J400 have no chroma channel.
|
I400 and J400 have no chroma channel.
|
||||||
|
|
||||||
# Color space
|
# Color space
|
||||||
|
|||||||
@ -560,6 +560,21 @@ int I210ToP210(const uint16_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert I410 to P410
|
||||||
|
LIBYUV_API
|
||||||
|
int I410ToP410(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_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
// Convert I012 to P012
|
// Convert I012 to P012
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int I012ToP012(const uint16_t* src_y,
|
int I012ToP012(const uint16_t* src_y,
|
||||||
@ -590,6 +605,21 @@ int I212ToP212(const uint16_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert I412 to P412
|
||||||
|
LIBYUV_API
|
||||||
|
int I412ToP412(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_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
// Convert I400 (grey) to I420.
|
// Convert I400 (grey) to I420.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int I400ToI420(const uint8_t* src_y,
|
int I400ToI420(const uint8_t* src_y,
|
||||||
@ -704,6 +734,81 @@ int P010ToI010(const uint16_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert P210 to I210.
|
||||||
|
LIBYUV_API
|
||||||
|
int P210ToI210(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Convert P410 to I410.
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToI410(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Convert P010 to I420.
|
||||||
|
LIBYUV_API
|
||||||
|
int P010ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert P210 to I420.
|
||||||
|
LIBYUV_API
|
||||||
|
int P210ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert P410 to I420.
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
// Convert P012 to I012.
|
// Convert P012 to I012.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int P012ToI012(const uint16_t* src_y,
|
int P012ToI012(const uint16_t* src_y,
|
||||||
|
|||||||
@ -1702,6 +1702,18 @@ int P210ToARGBMatrix(const uint16_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert P410 to ARGB with matrix.
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToARGBMatrix(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
uint8_t* dst_argb,
|
||||||
|
int dst_stride_argb,
|
||||||
|
const struct YuvConstants* yuvconstants,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
// Convert P010 to AR30 with matrix.
|
// Convert P010 to AR30 with matrix.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int P010ToAR30Matrix(const uint16_t* src_y,
|
int P010ToAR30Matrix(const uint16_t* src_y,
|
||||||
@ -1726,6 +1738,18 @@ int P210ToAR30Matrix(const uint16_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert P410 to AR30 with matrix.
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToAR30Matrix(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
uint8_t* dst_ar30,
|
||||||
|
int dst_stride_ar30,
|
||||||
|
const struct YuvConstants* yuvconstants,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
// P012 and P010 use most significant bits so the conversion is the same.
|
// P012 and P010 use most significant bits so the conversion is the same.
|
||||||
// Convert P012 to ARGB with matrix.
|
// Convert P012 to ARGB with matrix.
|
||||||
#define P012ToARGBMatrix P010ToARGBMatrix
|
#define P012ToARGBMatrix P010ToARGBMatrix
|
||||||
@ -1735,6 +1759,10 @@ int P210ToAR30Matrix(const uint16_t* src_y,
|
|||||||
#define P212ToARGBMatrix P210ToARGBMatrix
|
#define P212ToARGBMatrix P210ToARGBMatrix
|
||||||
// Convert P212 to AR30 with matrix.
|
// Convert P212 to AR30 with matrix.
|
||||||
#define P212ToAR30Matrix P210ToAR30Matrix
|
#define P212ToAR30Matrix P210ToAR30Matrix
|
||||||
|
// Convert P412 to ARGB with matrix.
|
||||||
|
#define P412ToARGBMatrix P410ToARGBMatrix
|
||||||
|
// Convert P412 to AR30 with matrix.
|
||||||
|
#define P412ToAR30Matrix P410ToAR30Matrix
|
||||||
|
|
||||||
// Convert P016 to ARGB with matrix.
|
// Convert P016 to ARGB with matrix.
|
||||||
#define P016ToARGBMatrix P010ToARGBMatrix
|
#define P016ToARGBMatrix P010ToARGBMatrix
|
||||||
@ -1744,6 +1772,10 @@ int P210ToAR30Matrix(const uint16_t* src_y,
|
|||||||
#define P216ToARGBMatrix P210ToARGBMatrix
|
#define P216ToARGBMatrix P210ToARGBMatrix
|
||||||
// Convert P216 to AR30 with matrix.
|
// Convert P216 to AR30 with matrix.
|
||||||
#define P216ToAR30Matrix P210ToAR30Matrix
|
#define P216ToAR30Matrix P210ToAR30Matrix
|
||||||
|
// Convert P416 to ARGB with matrix.
|
||||||
|
#define P416ToARGBMatrix P410ToARGBMatrix
|
||||||
|
// Convert P416 to AR30 with matrix.
|
||||||
|
#define P416ToAR30Matrix P410ToAR30Matrix
|
||||||
|
|
||||||
// Convert I420 with Alpha to preattenuated ARGB with matrix.
|
// Convert I420 with Alpha to preattenuated ARGB with matrix.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
|
|||||||
@ -128,6 +128,81 @@ int I420ToNV21(const uint8_t* src_y,
|
|||||||
int width,
|
int width,
|
||||||
int height);
|
int height);
|
||||||
|
|
||||||
|
// Convert I420 to P010.
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP010(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert I422 to P210.
|
||||||
|
LIBYUV_API
|
||||||
|
int I422ToP210(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert I444 to P410.
|
||||||
|
LIBYUV_API
|
||||||
|
int I444ToP410(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert I420 to P210.
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP210(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
// Convert I420 to P410.
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP410(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int I420ToYUY2(const uint8_t* src_y,
|
int I420ToYUY2(const uint8_t* src_y,
|
||||||
int src_stride_y,
|
int src_stride_y,
|
||||||
|
|||||||
@ -264,7 +264,7 @@ int I422Scale_12(const uint16_t* src_y,
|
|||||||
int dst_height,
|
int dst_height,
|
||||||
enum FilterMode filtering);
|
enum FilterMode filtering);
|
||||||
|
|
||||||
// Scales an NV12 image from the src width and height to the
|
// Scales an NV12, NV16 or NV24 image from the src width and height to the
|
||||||
// dst width and height.
|
// dst width and height.
|
||||||
// If filtering is kFilterNone, a simple nearest-neighbor algorithm is
|
// If filtering is kFilterNone, a simple nearest-neighbor algorithm is
|
||||||
// used. This produces basic (blocky) quality at the fastest speed.
|
// used. This produces basic (blocky) quality at the fastest speed.
|
||||||
@ -289,6 +289,21 @@ int NV12Scale(const uint8_t* src_y,
|
|||||||
int dst_height,
|
int dst_height,
|
||||||
enum FilterMode filtering);
|
enum FilterMode filtering);
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int NV16Scale(const uint8_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint8_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint8_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint8_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering);
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int NV24Scale(const uint8_t* src_y,
|
int NV24Scale(const uint8_t* src_y,
|
||||||
int src_stride_y,
|
int src_stride_y,
|
||||||
@ -304,6 +319,57 @@ int NV24Scale(const uint8_t* src_y,
|
|||||||
int dst_height,
|
int dst_height,
|
||||||
enum FilterMode filtering);
|
enum FilterMode filtering);
|
||||||
|
|
||||||
|
// Scales a P010, P210 or P410 image (10-bit, samples in the MSBs of uint16).
|
||||||
|
// Strides are in uint16 elements. Y and UV are converted to 10-bit LSB,
|
||||||
|
// scaled with ScalePlane_16 (kFilterBox included), then converted back to
|
||||||
|
// 10-bit MSB.
|
||||||
|
// Returns 0 if successful.
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P010Scale(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering);
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P210Scale(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering);
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410Scale(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
// Legacy API. Deprecated.
|
// Legacy API. Deprecated.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
|
|||||||
@ -53,7 +53,7 @@ extern "C" {
|
|||||||
// Secondary formats are converted in 2 steps.
|
// Secondary formats are converted in 2 steps.
|
||||||
// Auxilliary formats call primary converters.
|
// Auxilliary formats call primary converters.
|
||||||
enum FourCC {
|
enum FourCC {
|
||||||
// 12 Primary YUV formats: 5 planar, 4 biplanar, 2 packed.
|
// 15 Primary YUV formats: 6 planar, 7 biplanar, 2 packed.
|
||||||
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
|
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
|
||||||
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
|
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
|
||||||
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
|
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
|
||||||
@ -62,6 +62,9 @@ enum FourCC {
|
|||||||
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
|
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
|
||||||
FOURCC_NV16 = FOURCC('N', 'V', '1', '6'),
|
FOURCC_NV16 = FOURCC('N', 'V', '1', '6'),
|
||||||
FOURCC_NV24 = FOURCC('N', 'V', '2', '4'),
|
FOURCC_NV24 = FOURCC('N', 'V', '2', '4'),
|
||||||
|
FOURCC_P010 = FOURCC('P', '0', '1', '0'),
|
||||||
|
FOURCC_P210 = FOURCC('P', '2', '1', '0'),
|
||||||
|
FOURCC_P410 = FOURCC('P', '4', '1', '0'),
|
||||||
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
|
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
|
||||||
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
|
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
|
||||||
FOURCC_I010 = FOURCC('I', '0', '1', '0'), // bt.601 10 bit 420
|
FOURCC_I010 = FOURCC('I', '0', '1', '0'), // bt.601 10 bit 420
|
||||||
@ -88,7 +91,7 @@ enum FourCC {
|
|||||||
// 1 Primary Compressed YUV format.
|
// 1 Primary Compressed YUV format.
|
||||||
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
|
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
|
||||||
|
|
||||||
// 14 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
|
// 23 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
|
||||||
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
|
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
|
||||||
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
|
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
|
||||||
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
|
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
|
||||||
@ -116,8 +119,6 @@ enum FourCC {
|
|||||||
FOURCC_F210 = FOURCC('F', '2', '1', '0'), // bt.709 full range 10 bit 422
|
FOURCC_F210 = FOURCC('F', '2', '1', '0'), // bt.709 full range 10 bit 422
|
||||||
FOURCC_H210 = FOURCC('H', '2', '1', '0'), // bt.709 10 bit 422
|
FOURCC_H210 = FOURCC('H', '2', '1', '0'), // bt.709 10 bit 422
|
||||||
FOURCC_U210 = FOURCC('U', '2', '1', '0'), // bt.2020 10 bit 422
|
FOURCC_U210 = FOURCC('U', '2', '1', '0'), // bt.2020 10 bit 422
|
||||||
FOURCC_P010 = FOURCC('P', '0', '1', '0'),
|
|
||||||
FOURCC_P210 = FOURCC('P', '2', '1', '0'),
|
|
||||||
|
|
||||||
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
|
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
|
||||||
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
|
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
|
||||||
@ -197,6 +198,7 @@ enum FourCCBpp {
|
|||||||
FOURCC_BPP_H210 = 20,
|
FOURCC_BPP_H210 = 20,
|
||||||
FOURCC_BPP_P010 = 15,
|
FOURCC_BPP_P010 = 15,
|
||||||
FOURCC_BPP_P210 = 20,
|
FOURCC_BPP_P210 = 20,
|
||||||
|
FOURCC_BPP_P410 = 30,
|
||||||
FOURCC_BPP_MJPG = 0, // 0 means unknown.
|
FOURCC_BPP_MJPG = 0, // 0 means unknown.
|
||||||
FOURCC_BPP_H264 = 0,
|
FOURCC_BPP_H264 = 0,
|
||||||
FOURCC_BPP_IYUV = 12,
|
FOURCC_BPP_IYUV = 12,
|
||||||
|
|||||||
@ -1047,6 +1047,24 @@ int I210ToP210(const uint16_t* src_y,
|
|||||||
width, height, 1, 0, 10);
|
width, height, 1, 0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I410ToP410(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_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, 0, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int I012ToP012(const uint16_t* src_y,
|
int I012ToP012(const uint16_t* src_y,
|
||||||
int src_stride_y,
|
int src_stride_y,
|
||||||
@ -1083,6 +1101,24 @@ int I212ToP212(const uint16_t* src_y,
|
|||||||
width, height, 1, 0, 12);
|
width, height, 1, 0, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I412ToP412(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_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, 0, 0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
// 422 chroma is 1/2 width, 1x height
|
// 422 chroma is 1/2 width, 1x height
|
||||||
// 420 chroma is 1/2 width, 1/2 height
|
// 420 chroma is 1/2 width, 1/2 height
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
@ -1838,6 +1874,425 @@ int P010ToI010(const uint16_t* src_y,
|
|||||||
width, height, 1, 1, 10);
|
width, height, 1, 1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P210ToI210(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
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) {
|
||||||
|
return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
width, height, 1, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToI410(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
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) {
|
||||||
|
return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
width, height, 0, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvertPx10(const uint16_t** src_y,
|
||||||
|
int* src_stride_y,
|
||||||
|
const uint16_t** src_uv,
|
||||||
|
int* src_stride_uv,
|
||||||
|
int* height,
|
||||||
|
int subsample_y) {
|
||||||
|
const int abs_height = Abs(*height);
|
||||||
|
const int src_uv_height = SUBSAMPLE(abs_height, subsample_y, subsample_y);
|
||||||
|
if (*src_y) {
|
||||||
|
*src_y = *src_y + (ptrdiff_t)(abs_height - 1) * *src_stride_y;
|
||||||
|
*src_stride_y = -*src_stride_y;
|
||||||
|
}
|
||||||
|
*src_uv = *src_uv + (ptrdiff_t)(src_uv_height - 1) * *src_stride_uv;
|
||||||
|
*src_stride_uv = -*src_stride_uv;
|
||||||
|
*height = abs_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Px10ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y) {
|
||||||
|
const int scale16 = 256; // P*10 stores 10-bit in the MSBs.
|
||||||
|
int src_uv_width;
|
||||||
|
int dst_uv_width;
|
||||||
|
if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
|
||||||
|
height == 0 || height == INT_MIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (height < 0) {
|
||||||
|
InvertPx10(&src_y, &src_stride_y, &src_uv, &src_stride_uv, &height,
|
||||||
|
subsample_y);
|
||||||
|
}
|
||||||
|
src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
|
||||||
|
dst_uv_width = SUBSAMPLE(width, 1, 1);
|
||||||
|
|
||||||
|
if (dst_y) {
|
||||||
|
Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale16, width,
|
||||||
|
height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subsample_x && subsample_y) {
|
||||||
|
int y;
|
||||||
|
const int uv_packed = src_uv_width * 2;
|
||||||
|
const int uv_height = SUBSAMPLE(height, 1, 1);
|
||||||
|
void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
|
||||||
|
int width) = Convert16To8Row_C;
|
||||||
|
void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v,
|
||||||
|
int width) = SplitUVRow_C;
|
||||||
|
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_Any_NEON;
|
||||||
|
if (IS_ALIGNED(uv_packed, 16)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_Any_SSSE3;
|
||||||
|
if (IS_ALIGNED(uv_packed, 16)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_SSSE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(uv_packed, 32)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_Any_AVX512BW;
|
||||||
|
if (IS_ALIGNED(uv_packed, 64)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_AVX512BW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT16TO8ROW_RVV)
|
||||||
|
if (TestCpuFlag(kCpuHasRVV)) {
|
||||||
|
Convert16To8Row = Convert16To8Row_RVV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_SSE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
||||||
|
SplitUVRow = SplitUVRow_Any_SSE2;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 16)) {
|
||||||
|
SplitUVRow = SplitUVRow_SSE2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
SplitUVRow = SplitUVRow_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 32)) {
|
||||||
|
SplitUVRow = SplitUVRow_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_AVX512BW)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||||
|
SplitUVRow = SplitUVRow_Any_AVX512BW;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 64)) {
|
||||||
|
SplitUVRow = SplitUVRow_AVX512BW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
SplitUVRow = SplitUVRow_Any_NEON;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 16)) {
|
||||||
|
SplitUVRow = SplitUVRow_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
SplitUVRow = SplitUVRow_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_LSX)
|
||||||
|
if (TestCpuFlag(kCpuHasLSX)) {
|
||||||
|
SplitUVRow = SplitUVRow_Any_LSX;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 32)) {
|
||||||
|
SplitUVRow = SplitUVRow_LSX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_RVV)
|
||||||
|
if (TestCpuFlag(kCpuHasRVV)) {
|
||||||
|
SplitUVRow = SplitUVRow_RVV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
align_buffer_64(row_uv, ((uv_packed + 63) & ~63));
|
||||||
|
if (!row_uv) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (y = 0; y < uv_height; ++y) {
|
||||||
|
Convert16To8Row(src_uv, row_uv, scale16, uv_packed);
|
||||||
|
SplitUVRow(row_uv, dst_u, dst_v, src_uv_width);
|
||||||
|
src_uv += src_stride_uv;
|
||||||
|
dst_u += dst_stride_u;
|
||||||
|
dst_v += dst_stride_v;
|
||||||
|
}
|
||||||
|
free_aligned_buffer_64(row_uv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int y;
|
||||||
|
const int scale = 16384; // 10-bit LSB after SplitUVRow_16.
|
||||||
|
int row_stride;
|
||||||
|
void (*SplitUVRow_16)(const uint16_t* src_uv, uint16_t* dst_u,
|
||||||
|
uint16_t* dst_v, int depth, int width) =
|
||||||
|
SplitUVRow_16_C;
|
||||||
|
void (*Half16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
|
||||||
|
uint8_t* dst_uv, int scale, int width) =
|
||||||
|
subsample_x ? HalfRow_16To8_C
|
||||||
|
: ((width & 1) ? HalfWidthRow_16To8_Odd_C
|
||||||
|
: HalfWidthRow_16To8_C);
|
||||||
|
|
||||||
|
#if defined(HAS_SPLITUVROW_16_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
SplitUVRow_16 = SplitUVRow_16_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 16)) {
|
||||||
|
SplitUVRow_16 = SplitUVRow_16_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SPLITUVROW_16_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
SplitUVRow_16 = SplitUVRow_16_Any_NEON;
|
||||||
|
if (IS_ALIGNED(src_uv_width, 8)) {
|
||||||
|
SplitUVRow_16 = SplitUVRow_16_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (subsample_x) {
|
||||||
|
#if defined(HAS_HALFROW_16TO8_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
Half16To8 = HalfRow_16To8_Any_NEON;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 16)) {
|
||||||
|
Half16To8 = HalfRow_16To8_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
Half16To8 = HalfRow_16To8_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
Half16To8 = HalfRow_16To8_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
|
Half16To8 = HalfRow_16To8_Any_SSSE3;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 16)) {
|
||||||
|
Half16To8 = HalfRow_16To8_SSSE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
Half16To8 = HalfRow_16To8_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 32)) {
|
||||||
|
Half16To8 = HalfRow_16To8_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_AVX512BW)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||||
|
Half16To8 = HalfRow_16To8_Any_AVX512BW;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 64)) {
|
||||||
|
Half16To8 = HalfRow_16To8_AVX512BW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFROW_16TO8_RVV)
|
||||||
|
if (TestCpuFlag(kCpuHasRVV)) {
|
||||||
|
Half16To8 = HalfRow_16To8_RVV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (IS_ALIGNED(width, 2)) {
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_Any_NEON;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 8)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_Any_SSSE3;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 8)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_SSSE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 16)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_Any_AVX512BW;
|
||||||
|
if (IS_ALIGNED(dst_uv_width, 32)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_AVX512BW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_HALFWIDTHROW_16TO8_RVV)
|
||||||
|
if (TestCpuFlag(kCpuHasRVV)) {
|
||||||
|
Half16To8 = HalfWidthRow_16To8_RVV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
row_stride = (src_uv_width + 31) & ~31;
|
||||||
|
align_buffer_64(row_u, (size_t)row_stride * sizeof(uint16_t) * 4u);
|
||||||
|
if (!row_u) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
uint16_t* row_u0 = (uint16_t*)row_u;
|
||||||
|
uint16_t* row_u1 = row_u0 + row_stride;
|
||||||
|
uint16_t* row_v0 = row_u1 + row_stride;
|
||||||
|
uint16_t* row_v1 = row_v0 + row_stride;
|
||||||
|
for (y = 0; y < height - 1; y += 2) {
|
||||||
|
SplitUVRow_16(src_uv, row_u0, row_v0, 10, src_uv_width);
|
||||||
|
SplitUVRow_16(src_uv + src_stride_uv, row_u1, row_v1, 10, src_uv_width);
|
||||||
|
Half16To8(row_u0, row_stride, dst_u, scale, dst_uv_width);
|
||||||
|
Half16To8(row_v0, row_stride, dst_v, scale, dst_uv_width);
|
||||||
|
src_uv += src_stride_uv * 2;
|
||||||
|
dst_u += dst_stride_u;
|
||||||
|
dst_v += dst_stride_v;
|
||||||
|
}
|
||||||
|
if (height & 1) {
|
||||||
|
SplitUVRow_16(src_uv, row_u0, row_v0, 10, src_uv_width);
|
||||||
|
Half16To8(row_u0, 0, dst_u, scale, dst_uv_width);
|
||||||
|
Half16To8(row_v0, 0, dst_v, scale, dst_uv_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_aligned_buffer_64(row_u);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P010ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
width, height, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P210ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
width, height, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToI420(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_u,
|
||||||
|
int dst_stride_u,
|
||||||
|
uint8_t* dst_v,
|
||||||
|
int dst_stride_v,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
width, height, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int P012ToI012(const uint16_t* src_y,
|
int P012ToI012(const uint16_t* src_y,
|
||||||
int src_stride_y,
|
int src_stride_y,
|
||||||
|
|||||||
@ -2079,6 +2079,74 @@ int P210ToARGBMatrix(const uint16_t* src_y,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToARGBMatrix(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
uint8_t* dst_argb,
|
||||||
|
int dst_stride_argb,
|
||||||
|
const struct YuvConstants* yuvconstants,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
int y;
|
||||||
|
void (*P410ToARGBRow)(
|
||||||
|
const uint16_t* y_buf, const uint16_t* uv_buf, uint8_t* rgb_buf,
|
||||||
|
const struct YuvConstants* yuvconstants, int width) = P410ToARGBRow_C;
|
||||||
|
assert(yuvconstants);
|
||||||
|
if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0 ||
|
||||||
|
height == INT_MIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Negative height means invert the image.
|
||||||
|
if (height < 0) {
|
||||||
|
height = -height;
|
||||||
|
dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb;
|
||||||
|
dst_stride_argb = -dst_stride_argb;
|
||||||
|
}
|
||||||
|
#if defined(HAS_P410TOARGBROW_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_Any_SSSE3;
|
||||||
|
if (IS_ALIGNED(width, 8)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_SSSE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOARGBROW_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(width, 16)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOARGBROW_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_Any_NEON;
|
||||||
|
if (IS_ALIGNED(width, 8)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOARGBROW_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOARGBROW_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
P410ToARGBRow = P410ToARGBRow_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
P410ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
|
||||||
|
dst_argb += dst_stride_argb;
|
||||||
|
src_y += src_stride_y;
|
||||||
|
src_uv += src_stride_uv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int P010ToAR30Matrix(const uint16_t* src_y,
|
int P010ToAR30Matrix(const uint16_t* src_y,
|
||||||
int src_stride_y,
|
int src_stride_y,
|
||||||
@ -2217,6 +2285,74 @@ int P210ToAR30Matrix(const uint16_t* src_y,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410ToAR30Matrix(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
uint8_t* dst_ar30,
|
||||||
|
int dst_stride_ar30,
|
||||||
|
const struct YuvConstants* yuvconstants,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
int y;
|
||||||
|
void (*P410ToAR30Row)(
|
||||||
|
const uint16_t* y_buf, const uint16_t* uv_buf, uint8_t* rgb_buf,
|
||||||
|
const struct YuvConstants* yuvconstants, int width) = P410ToAR30Row_C;
|
||||||
|
assert(yuvconstants);
|
||||||
|
if (!src_y || !src_uv || !dst_ar30 || width <= 0 || height == 0 ||
|
||||||
|
height == INT_MIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Negative height means invert the image.
|
||||||
|
if (height < 0) {
|
||||||
|
height = -height;
|
||||||
|
dst_ar30 = dst_ar30 + (ptrdiff_t)(height - 1) * dst_stride_ar30;
|
||||||
|
dst_stride_ar30 = -dst_stride_ar30;
|
||||||
|
}
|
||||||
|
#if defined(HAS_P410TOAR30ROW_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_Any_SSSE3;
|
||||||
|
if (IS_ALIGNED(width, 8)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_SSSE3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOAR30ROW_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(width, 16)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOAR30ROW_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_Any_NEON;
|
||||||
|
if (IS_ALIGNED(width, 8)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOAR30ROW_SVE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSVE2)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_SVE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_P410TOAR30ROW_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
P410ToAR30Row = P410ToAR30Row_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
P410ToAR30Row(src_y, src_uv, dst_ar30, yuvconstants, width);
|
||||||
|
dst_ar30 += dst_stride_ar30;
|
||||||
|
src_y += src_stride_y;
|
||||||
|
src_uv += src_stride_uv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert I420 with Alpha to preattenuated ARGB with matrix.
|
// Convert I420 with Alpha to preattenuated ARGB with matrix.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int I420AlphaToARGBMatrix(const uint8_t* src_y,
|
int I420AlphaToARGBMatrix(const uint8_t* src_y,
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "libyuv/convert_from.h"
|
#include "libyuv/convert_from.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "libyuv/convert.h" // For I420Copy
|
#include "libyuv/convert.h" // For I420Copy
|
||||||
#include "libyuv/cpu_id.h"
|
#include "libyuv/cpu_id.h"
|
||||||
@ -710,6 +711,296 @@ int I420ToNV21(const uint8_t* src_y,
|
|||||||
width, height);
|
width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int I4xxToPxxx(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y) {
|
||||||
|
int y;
|
||||||
|
int uv_width;
|
||||||
|
int uv_height;
|
||||||
|
int row_stride;
|
||||||
|
void (*Convert8To16Row)(const uint8_t* src_y, uint16_t* dst_y, int bits,
|
||||||
|
int width) = Convert8To16Row_C;
|
||||||
|
void (*MergeUVRow_16)(const uint16_t* src_u, const uint16_t* src_v,
|
||||||
|
uint16_t* dst_uv, int depth, int width) =
|
||||||
|
MergeUVRow_16_C;
|
||||||
|
if ((!src_y && dst_y) || !src_u || !src_v || !dst_y || !dst_uv ||
|
||||||
|
width <= 0 || height == 0 || height == INT_MIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (height < 0) {
|
||||||
|
height = -height;
|
||||||
|
uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
|
||||||
|
src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
|
||||||
|
src_u = src_u + (ptrdiff_t)(uv_height - 1) * src_stride_u;
|
||||||
|
src_v = src_v + (ptrdiff_t)(uv_height - 1) * src_stride_v;
|
||||||
|
src_stride_y = -src_stride_y;
|
||||||
|
src_stride_u = -src_stride_u;
|
||||||
|
src_stride_v = -src_stride_v;
|
||||||
|
} else {
|
||||||
|
uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
|
||||||
|
}
|
||||||
|
uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
|
||||||
|
|
||||||
|
Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 10, width,
|
||||||
|
height);
|
||||||
|
ConvertToMSBPlane_16(dst_y, dst_stride_y, dst_y, dst_stride_y, width, height,
|
||||||
|
10);
|
||||||
|
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_SSE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_Any_SSE2;
|
||||||
|
if (IS_ALIGNED(uv_width, 16)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_SSE2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(uv_width, 32)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_AVX512BW)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX512BW)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_Any_AVX512BW;
|
||||||
|
if (IS_ALIGNED(uv_width, 64)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_AVX512BW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_Any_NEON;
|
||||||
|
if (IS_ALIGNED(uv_width, 16)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_CONVERT8TO16ROW_RVV)
|
||||||
|
if (TestCpuFlag(kCpuHasRVV)) {
|
||||||
|
Convert8To16Row = Convert8To16Row_RVV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_MERGEUVROW_16_AVX2)
|
||||||
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
|
MergeUVRow_16 = MergeUVRow_16_Any_AVX2;
|
||||||
|
if (IS_ALIGNED(uv_width, 8)) {
|
||||||
|
MergeUVRow_16 = MergeUVRow_16_AVX2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_MERGEUVROW_16_NEON)
|
||||||
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
|
MergeUVRow_16 = MergeUVRow_16_Any_NEON;
|
||||||
|
if (IS_ALIGNED(uv_width, 8)) {
|
||||||
|
MergeUVRow_16 = MergeUVRow_16_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_MERGEUVROW_16_SME)
|
||||||
|
if (TestCpuFlag(kCpuHasSME)) {
|
||||||
|
MergeUVRow_16 = MergeUVRow_16_SME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
row_stride = (uv_width + 31) & ~31;
|
||||||
|
align_buffer_64(row_u, (size_t)row_stride * sizeof(uint16_t) * 2u);
|
||||||
|
if (!row_u) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
uint16_t* row_u16 = (uint16_t*)row_u;
|
||||||
|
uint16_t* row_v16 = row_u16 + row_stride;
|
||||||
|
for (y = 0; y < uv_height; ++y) {
|
||||||
|
Convert8To16Row(src_u, row_u16, 10, uv_width);
|
||||||
|
Convert8To16Row(src_v, row_v16, 10, uv_width);
|
||||||
|
MergeUVRow_16(row_u16, row_v16, dst_uv, 10, uv_width);
|
||||||
|
src_u += src_stride_u;
|
||||||
|
src_v += src_stride_v;
|
||||||
|
dst_uv += dst_stride_uv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_aligned_buffer_64(row_u);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP010(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return I4xxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I422ToP210(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return I4xxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I444ToP410(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return I4xxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int I420ToPxxx(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int dst_uv_width,
|
||||||
|
int (*i4xx_to_pxxx)(const uint8_t*,
|
||||||
|
int,
|
||||||
|
const uint8_t*,
|
||||||
|
int,
|
||||||
|
const uint8_t*,
|
||||||
|
int,
|
||||||
|
uint16_t*,
|
||||||
|
int,
|
||||||
|
uint16_t*,
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
int)) {
|
||||||
|
int r;
|
||||||
|
int abs_height;
|
||||||
|
uint64_t uv_size;
|
||||||
|
uint64_t total;
|
||||||
|
if ((!src_y && dst_y) || !src_u || !src_v || !dst_y || !dst_uv ||
|
||||||
|
width <= 0 || height == 0 || height == INT_MIN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
abs_height = Abs(height);
|
||||||
|
if (height < 0) {
|
||||||
|
const int src_uv_height = SUBSAMPLE(abs_height, 1, 1);
|
||||||
|
src_y = src_y + (ptrdiff_t)(abs_height - 1) * src_stride_y;
|
||||||
|
src_u = src_u + (ptrdiff_t)(src_uv_height - 1) * src_stride_u;
|
||||||
|
src_v = src_v + (ptrdiff_t)(src_uv_height - 1) * src_stride_v;
|
||||||
|
src_stride_y = -src_stride_y;
|
||||||
|
src_stride_u = -src_stride_u;
|
||||||
|
src_stride_v = -src_stride_v;
|
||||||
|
height = abs_height;
|
||||||
|
}
|
||||||
|
uv_size = (uint64_t)dst_uv_width * (uint64_t)abs_height;
|
||||||
|
total = uv_size * 2u;
|
||||||
|
if (total > SIZE_MAX) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
align_buffer_64(plane_u, (size_t)total);
|
||||||
|
if (!plane_u) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
uint8_t* tmp_u = plane_u;
|
||||||
|
uint8_t* tmp_v = plane_u + uv_size;
|
||||||
|
r = I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, NULL, 0, tmp_u, dst_uv_width, tmp_v,
|
||||||
|
dst_uv_width, width, height, dst_uv_width, abs_height);
|
||||||
|
if (!r) {
|
||||||
|
r = i4xx_to_pxxx(src_y, src_stride_y, tmp_u, dst_uv_width, tmp_v,
|
||||||
|
dst_uv_width, dst_y, dst_stride_y, dst_uv,
|
||||||
|
dst_stride_uv, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_aligned_buffer_64(plane_u);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP210(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return I420ToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, (Abs(width) + 1) >> 1, I422ToP210);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int I420ToP410(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,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int width,
|
||||||
|
int height) {
|
||||||
|
return I420ToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
||||||
|
src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
width, height, Abs(width), I444ToP410);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert I420 to specified format
|
// Convert I420 to specified format
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int ConvertFromI420(const uint8_t* y,
|
int ConvertFromI420(const uint8_t* y,
|
||||||
@ -851,6 +1142,64 @@ int ConvertFromI420(const uint8_t* y,
|
|||||||
free_aligned_buffer_64(temp_v);
|
free_aligned_buffer_64(temp_v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FOURCC_P010:
|
||||||
|
case FOURCC_P210: {
|
||||||
|
const int abs_height = Abs(height);
|
||||||
|
const int uv_min = ((width + 1) / 2) * 2;
|
||||||
|
int dst_stride_y;
|
||||||
|
int dst_stride_uv;
|
||||||
|
uint16_t* dst_y16;
|
||||||
|
uint16_t* dst_uv16;
|
||||||
|
if (dst_sample_stride == 0) {
|
||||||
|
dst_stride_y = width;
|
||||||
|
dst_stride_uv = uv_min;
|
||||||
|
} else {
|
||||||
|
if (dst_sample_stride & 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dst_stride_y = dst_sample_stride / 2;
|
||||||
|
dst_stride_uv = dst_sample_stride / 2;
|
||||||
|
if (Abs(dst_stride_uv) < uv_min) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_y16 = (uint16_t*)dst_sample;
|
||||||
|
dst_uv16 = dst_y16 + (ptrdiff_t)dst_stride_y * abs_height;
|
||||||
|
if (format == FOURCC_P010) {
|
||||||
|
r = I420ToP010(y, y_stride, u, u_stride, v, v_stride, dst_y16,
|
||||||
|
dst_stride_y, dst_uv16, dst_stride_uv, width, height);
|
||||||
|
} else {
|
||||||
|
r = I420ToP210(y, y_stride, u, u_stride, v, v_stride, dst_y16,
|
||||||
|
dst_stride_y, dst_uv16, dst_stride_uv, width, height);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOURCC_P410: {
|
||||||
|
const int abs_height = Abs(height);
|
||||||
|
const int uv_min = width * 2;
|
||||||
|
int dst_stride_y;
|
||||||
|
int dst_stride_uv;
|
||||||
|
uint16_t* dst_y16;
|
||||||
|
uint16_t* dst_uv16;
|
||||||
|
if (dst_sample_stride == 0) {
|
||||||
|
dst_stride_y = width;
|
||||||
|
dst_stride_uv = uv_min;
|
||||||
|
} else {
|
||||||
|
if (dst_sample_stride & 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dst_stride_y = dst_sample_stride / 2;
|
||||||
|
dst_stride_uv = dst_sample_stride;
|
||||||
|
if (Abs(dst_stride_uv) < uv_min) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_y16 = (uint16_t*)dst_sample;
|
||||||
|
dst_uv16 = dst_y16 + (ptrdiff_t)dst_stride_y * abs_height;
|
||||||
|
r = I420ToP410(y, y_stride, u, u_stride, v, v_stride, dst_y16,
|
||||||
|
dst_stride_y, dst_uv16, dst_stride_uv, width, height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Triplanar formats
|
// Triplanar formats
|
||||||
case FOURCC_I420:
|
case FOURCC_I420:
|
||||||
case FOURCC_YV12: {
|
case FOURCC_YV12: {
|
||||||
|
|||||||
@ -435,6 +435,42 @@ int ConvertToARGB(const uint8_t* sample,
|
|||||||
r = NV24ToARGB(src, src_width, src_uv, aligned_src_width * 2, dst_argb,
|
r = NV24ToARGB(src, src_width, src_uv, aligned_src_width * 2, dst_argb,
|
||||||
dst_stride_argb, crop_width, inv_crop_height);
|
dst_stride_argb, crop_width, inv_crop_height);
|
||||||
break;
|
break;
|
||||||
|
case FOURCC_P010: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)(crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
|
||||||
|
r = P010ToARGBMatrix(src_y16, src_width, src_uv16, aligned_src_width,
|
||||||
|
dst_argb, dst_stride_argb, &kYuvI601Constants,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOURCC_P210: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)crop_y * aligned_src_width) + ((crop_x / 2) * 2);
|
||||||
|
r = P210ToARGBMatrix(src_y16, src_width, src_uv16, aligned_src_width,
|
||||||
|
dst_argb, dst_stride_argb, &kYuvI601Constants,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOURCC_P410: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)crop_y * src_width * 2) + crop_x * 2;
|
||||||
|
r = P410ToARGBMatrix(src_y16, src_width, src_uv16, src_width * 2,
|
||||||
|
dst_argb, dst_stride_argb, &kYuvI601Constants,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Triplanar formats
|
// Triplanar formats
|
||||||
case FOURCC_I420:
|
case FOURCC_I420:
|
||||||
case FOURCC_YV12: {
|
case FOURCC_YV12: {
|
||||||
|
|||||||
@ -378,6 +378,42 @@ int ConvertToI420(const uint8_t* sample,
|
|||||||
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
crop_width, inv_crop_height);
|
crop_width, inv_crop_height);
|
||||||
break;
|
break;
|
||||||
|
case FOURCC_P010: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)(crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
|
||||||
|
r = P010ToI420(src_y16, src_width, src_uv16, aligned_src_width, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOURCC_P210: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)crop_y * aligned_src_width) + ((crop_x / 2) * 2);
|
||||||
|
r = P210ToI420(src_y16, src_width, src_uv16, aligned_src_width, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOURCC_P410: {
|
||||||
|
const uint16_t* src16 = (const uint16_t*)sample;
|
||||||
|
const uint16_t* src_y16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * crop_y + crop_x);
|
||||||
|
const uint16_t* src_uv16 =
|
||||||
|
src16 + ((ptrdiff_t)src_width * abs_src_height) +
|
||||||
|
((ptrdiff_t)crop_y * src_width * 2) + crop_x * 2;
|
||||||
|
r = P410ToI420(src_y16, src_width, src_uv16, src_width * 2, dst_y,
|
||||||
|
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
|
||||||
|
crop_width, inv_crop_height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Triplanar formats
|
// Triplanar formats
|
||||||
case FOURCC_I420:
|
case FOURCC_I420:
|
||||||
case FOURCC_YV12: {
|
case FOURCC_YV12: {
|
||||||
|
|||||||
296
source/scale.cc
296
source/scale.cc
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libyuv/cpu_id.h"
|
#include "libyuv/cpu_id.h"
|
||||||
@ -2599,8 +2600,187 @@ int I422Scale_12(const uint16_t* src_y,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale an NV12 image.
|
// Scale NV12 / NV16 / NV24. subsample_x/y are 1 to half that axis, else 0.
|
||||||
// This function in turn calls a scaling function for each plane.
|
|
||||||
|
static int NVScale(const uint8_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint8_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint8_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint8_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y) {
|
||||||
|
int r;
|
||||||
|
int src_uv_width;
|
||||||
|
int src_uv_height;
|
||||||
|
int dst_uv_width;
|
||||||
|
int dst_uv_height;
|
||||||
|
|
||||||
|
if (!src_y || !src_uv || src_width <= 0 || src_height == 0 ||
|
||||||
|
src_height == INT_MIN || !dst_y || !dst_uv || dst_width <= 0 ||
|
||||||
|
dst_height <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
src_uv_width = SUBSAMPLE(src_width, subsample_x, subsample_x);
|
||||||
|
src_uv_height = SUBSAMPLE(src_height, subsample_y, subsample_y);
|
||||||
|
dst_uv_width = SUBSAMPLE(dst_width, subsample_x, subsample_x);
|
||||||
|
dst_uv_height = SUBSAMPLE(dst_height, subsample_y, subsample_y);
|
||||||
|
|
||||||
|
r = ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y,
|
||||||
|
dst_stride_y, dst_width, dst_height, filtering);
|
||||||
|
if (r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = UVScale(src_uv, src_stride_uv, src_uv_width, src_uv_height, dst_uv,
|
||||||
|
dst_stride_uv, dst_uv_width, dst_uv_height, filtering);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale P010 / P210 / P410. subsample_x/y are 1 to half that axis, else 0.
|
||||||
|
// Samples are 10-bit in the MSBs. Convert to 10-bit LSB, ScalePlane_16, then
|
||||||
|
// back to MSB. UVScale_16 cannot general-scale, so UV is split then merged.
|
||||||
|
|
||||||
|
static int PxxxScale(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y) {
|
||||||
|
int r;
|
||||||
|
int src_uv_width;
|
||||||
|
int src_uv_height;
|
||||||
|
int dst_uv_width;
|
||||||
|
int dst_uv_height;
|
||||||
|
size_t src_uv_plane;
|
||||||
|
size_t dst_uv_plane;
|
||||||
|
size_t src_uv_bytes;
|
||||||
|
size_t dst_uv_bytes;
|
||||||
|
|
||||||
|
if (!src_y || !src_uv || src_width <= 0 || src_height == 0 ||
|
||||||
|
src_height == INT_MIN || !dst_y || !dst_uv || dst_width <= 0 ||
|
||||||
|
dst_height <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// ConvertToLSBPlane_16 / SplitUVPlane_16 invert dst, not src. Point both
|
||||||
|
// planes at the last row so ScalePlane_16 and the UV split see a top-down
|
||||||
|
// image.
|
||||||
|
if (src_height < 0) {
|
||||||
|
const int abs_height = -src_height;
|
||||||
|
const int src_uv_h = SUBSAMPLE(abs_height, subsample_y, subsample_y);
|
||||||
|
src_y = src_y + (ptrdiff_t)(abs_height - 1) * src_stride_y;
|
||||||
|
src_stride_y = -src_stride_y;
|
||||||
|
src_uv = src_uv + (ptrdiff_t)(src_uv_h - 1) * src_stride_uv;
|
||||||
|
src_stride_uv = -src_stride_uv;
|
||||||
|
src_height = abs_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_uv_width = SUBSAMPLE(src_width, subsample_x, subsample_x);
|
||||||
|
src_uv_height = SUBSAMPLE(src_height, subsample_y, subsample_y);
|
||||||
|
dst_uv_width = SUBSAMPLE(dst_width, subsample_x, subsample_x);
|
||||||
|
dst_uv_height = SUBSAMPLE(dst_height, subsample_y, subsample_y);
|
||||||
|
|
||||||
|
if (src_width == dst_width && src_height == dst_height) {
|
||||||
|
r = ScalePlane_16(src_y, src_stride_y, src_width, src_height, dst_y,
|
||||||
|
dst_stride_y, dst_width, dst_height, filtering);
|
||||||
|
} else {
|
||||||
|
size_t src_y_plane;
|
||||||
|
size_t src_y_bytes;
|
||||||
|
if ((size_t)src_width > SIZE_MAX / (size_t)src_height) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
src_y_plane = (size_t)src_width * (size_t)src_height;
|
||||||
|
if (src_y_plane > SIZE_MAX / sizeof(uint16_t)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
src_y_bytes = src_y_plane * sizeof(uint16_t);
|
||||||
|
align_buffer_64(src_y_lsb, src_y_bytes);
|
||||||
|
if (!src_y_lsb) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ConvertToLSBPlane_16(src_y, src_stride_y, (uint16_t*)src_y_lsb, src_width,
|
||||||
|
src_width, src_height, 10);
|
||||||
|
r = ScalePlane_16((uint16_t*)src_y_lsb, src_width, src_width, src_height,
|
||||||
|
dst_y, dst_stride_y, dst_width, dst_height, filtering);
|
||||||
|
if (r == 0) {
|
||||||
|
ConvertToMSBPlane_16(dst_y, dst_stride_y, dst_y, dst_stride_y, dst_width,
|
||||||
|
dst_height, 10);
|
||||||
|
}
|
||||||
|
free_aligned_buffer_64(src_y_lsb);
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_uv_width == dst_uv_width && src_uv_height == dst_uv_height &&
|
||||||
|
src_uv_width <= INT_MAX / 2) {
|
||||||
|
CopyPlane_16(src_uv, src_stride_uv, dst_uv, dst_stride_uv, src_uv_width * 2,
|
||||||
|
src_uv_height);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_uv_width <= 0 || src_uv_height <= 0 || dst_uv_width <= 0 ||
|
||||||
|
dst_uv_height <= 0 ||
|
||||||
|
(size_t)src_uv_width > SIZE_MAX / (size_t)src_uv_height ||
|
||||||
|
(size_t)dst_uv_width > SIZE_MAX / (size_t)dst_uv_height) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
src_uv_plane = (size_t)src_uv_width * (size_t)src_uv_height;
|
||||||
|
dst_uv_plane = (size_t)dst_uv_width * (size_t)dst_uv_height;
|
||||||
|
if (src_uv_plane > SIZE_MAX / (2u * sizeof(uint16_t)) ||
|
||||||
|
dst_uv_plane > SIZE_MAX / (2u * sizeof(uint16_t))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
src_uv_bytes = src_uv_plane * sizeof(uint16_t) * 2u;
|
||||||
|
dst_uv_bytes = dst_uv_plane * sizeof(uint16_t) * 2u;
|
||||||
|
|
||||||
|
align_buffer_64(src_uv_planes, src_uv_bytes);
|
||||||
|
align_buffer_64(dst_uv_planes, dst_uv_bytes);
|
||||||
|
if (!src_uv_planes || !dst_uv_planes) {
|
||||||
|
free_aligned_buffer_64(src_uv_planes);
|
||||||
|
free_aligned_buffer_64(dst_uv_planes);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint16_t* src_u = (uint16_t*)src_uv_planes;
|
||||||
|
uint16_t* src_v = src_u + src_uv_plane;
|
||||||
|
uint16_t* dst_u = (uint16_t*)dst_uv_planes;
|
||||||
|
uint16_t* dst_v = dst_u + dst_uv_plane;
|
||||||
|
|
||||||
|
SplitUVPlane_16(src_uv, src_stride_uv, src_u, src_uv_width, src_v,
|
||||||
|
src_uv_width, src_uv_width, src_uv_height, 10);
|
||||||
|
r = ScalePlane_16(src_u, src_uv_width, src_uv_width, src_uv_height, dst_u,
|
||||||
|
dst_uv_width, dst_uv_width, dst_uv_height, filtering);
|
||||||
|
if (r == 0) {
|
||||||
|
r = ScalePlane_16(src_v, src_uv_width, src_uv_width, src_uv_height, dst_v,
|
||||||
|
dst_uv_width, dst_uv_width, dst_uv_height, filtering);
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
MergeUVPlane_16(dst_u, dst_uv_width, dst_v, dst_uv_width, dst_uv,
|
||||||
|
dst_stride_uv, dst_uv_width, dst_uv_height, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_aligned_buffer_64(src_uv_planes);
|
||||||
|
free_aligned_buffer_64(dst_uv_planes);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int NV12Scale(const uint8_t* src_y,
|
int NV12Scale(const uint8_t* src_y,
|
||||||
@ -2616,26 +2796,28 @@ int NV12Scale(const uint8_t* src_y,
|
|||||||
int dst_width,
|
int dst_width,
|
||||||
int dst_height,
|
int dst_height,
|
||||||
enum FilterMode filtering) {
|
enum FilterMode filtering) {
|
||||||
int r;
|
return NVScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
dst_width, dst_height, filtering, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!src_y || !src_uv || src_width <= 0 || src_height == 0 ||
|
LIBYUV_API
|
||||||
src_height == INT_MIN || !dst_y || !dst_uv || dst_width <= 0 ||
|
int NV16Scale(const uint8_t* src_y,
|
||||||
dst_height <= 0) {
|
int src_stride_y,
|
||||||
return -1;
|
const uint8_t* src_uv,
|
||||||
}
|
int src_stride_uv,
|
||||||
int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
|
int src_width,
|
||||||
int src_halfheight = SUBSAMPLE(src_height, 1, 1);
|
int src_height,
|
||||||
int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
|
uint8_t* dst_y,
|
||||||
int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
|
int dst_stride_y,
|
||||||
|
uint8_t* dst_uv,
|
||||||
r = ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y,
|
int dst_stride_uv,
|
||||||
dst_stride_y, dst_width, dst_height, filtering);
|
int dst_width,
|
||||||
if (r != 0) {
|
int dst_height,
|
||||||
return r;
|
enum FilterMode filtering) {
|
||||||
}
|
return NVScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
r = UVScale(src_uv, src_stride_uv, src_halfwidth, src_halfheight, dst_uv,
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
dst_stride_uv, dst_halfwidth, dst_halfheight, filtering);
|
dst_width, dst_height, filtering, 1, 0);
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
@ -2652,22 +2834,66 @@ int NV24Scale(const uint8_t* src_y,
|
|||||||
int dst_width,
|
int dst_width,
|
||||||
int dst_height,
|
int dst_height,
|
||||||
enum FilterMode filtering) {
|
enum FilterMode filtering) {
|
||||||
int r;
|
return NVScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
dst_width, dst_height, filtering, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!src_y || !src_uv || src_width <= 0 || src_height == 0 ||
|
LIBYUV_API
|
||||||
src_height == INT_MIN || !dst_y || !dst_uv || dst_width <= 0 ||
|
int P010Scale(const uint16_t* src_y,
|
||||||
dst_height <= 0) {
|
int src_stride_y,
|
||||||
return -1;
|
const uint16_t* src_uv,
|
||||||
}
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering) {
|
||||||
|
return PxxxScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
dst_width, dst_height, filtering, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
r = ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y,
|
LIBYUV_API
|
||||||
dst_stride_y, dst_width, dst_height, filtering);
|
int P210Scale(const uint16_t* src_y,
|
||||||
if (r != 0) {
|
int src_stride_y,
|
||||||
return r;
|
const uint16_t* src_uv,
|
||||||
}
|
int src_stride_uv,
|
||||||
r = UVScale(src_uv, src_stride_uv, src_width, src_height, dst_uv,
|
int src_width,
|
||||||
dst_stride_uv, dst_width, dst_height, filtering);
|
int src_height,
|
||||||
return r;
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering) {
|
||||||
|
return PxxxScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
dst_width, dst_height, filtering, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBYUV_API
|
||||||
|
int P410Scale(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering) {
|
||||||
|
return PxxxScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
|
||||||
|
dst_width, dst_height, filtering, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated api
|
// Deprecated api
|
||||||
|
|||||||
@ -177,6 +177,11 @@ TESTBPTOP(NV21, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2, 8, 1, 1)
|
|||||||
TESTBPTOP(MM21, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2, 8, 16, 32)
|
TESTBPTOP(MM21, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2, 8, 16, 32)
|
||||||
TESTBPTOP(P010, uint16_t, 2, 2, 2, I010, uint16_t, 2, 2, 2, 10, 1, 1)
|
TESTBPTOP(P010, uint16_t, 2, 2, 2, I010, uint16_t, 2, 2, 2, 10, 1, 1)
|
||||||
TESTBPTOP(P012, uint16_t, 2, 2, 2, I012, uint16_t, 2, 2, 2, 12, 1, 1)
|
TESTBPTOP(P012, uint16_t, 2, 2, 2, I012, uint16_t, 2, 2, 2, 12, 1, 1)
|
||||||
|
TESTBPTOP(P210, uint16_t, 2, 2, 1, I210, uint16_t, 2, 2, 1, 10, 1, 1)
|
||||||
|
TESTBPTOP(P410, uint16_t, 2, 1, 1, I410, uint16_t, 2, 1, 1, 10, 1, 1)
|
||||||
|
TESTBPTOP(P010, uint16_t, 2, 2, 2, I420, uint8_t, 1, 2, 2, 10, 1, 1)
|
||||||
|
TESTBPTOP(P210, uint16_t, 2, 2, 1, I420, uint8_t, 1, 2, 2, 10, 1, 1)
|
||||||
|
TESTBPTOP(P410, uint16_t, 2, 1, 1, I420, uint8_t, 1, 2, 2, 10, 1, 1)
|
||||||
|
|
||||||
// Provide matrix wrappers for full range bt.709
|
// Provide matrix wrappers for full range bt.709
|
||||||
#define F420ToABGR(a, b, c, d, e, f, g, h, i, j) \
|
#define F420ToABGR(a, b, c, d, e, f, g, h, i, j) \
|
||||||
@ -499,6 +504,60 @@ TESTBPTOB(NV21, 2, 2, YUV24, RAW, 3)
|
|||||||
TESTBPTOB(NV12, 2, 2, RGB565, RGB565, 2)
|
TESTBPTOB(NV12, 2, 2, RGB565, RGB565, 2)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TESTBP16TOBTRANSITIVE(FMT_BP, FMT_PLANAR) \
|
||||||
|
TEST_F(LibYUVConvertTest, FMT_BP##ToARGB_Matches##FMT_PLANAR) { \
|
||||||
|
const int kWidth = benchmark_width_ | 1; \
|
||||||
|
const int kHeight = benchmark_height_; \
|
||||||
|
const int kPixels = kWidth * kHeight; \
|
||||||
|
align_buffer_page_end(src_y, kPixels * 2); \
|
||||||
|
align_buffer_page_end(src_uv, kPixels * 4); \
|
||||||
|
align_buffer_page_end(plane_y, kPixels * 2); \
|
||||||
|
align_buffer_page_end(plane_u, kPixels * 2); \
|
||||||
|
align_buffer_page_end(plane_v, kPixels * 2); \
|
||||||
|
align_buffer_page_end(dst_bp, kPixels * 4); \
|
||||||
|
align_buffer_page_end(dst_planar, kPixels * 4); \
|
||||||
|
uint16_t* src_y16 = reinterpret_cast<uint16_t*>(src_y); \
|
||||||
|
uint16_t* src_uv16 = reinterpret_cast<uint16_t*>(src_uv); \
|
||||||
|
uint16_t* plane_y16 = reinterpret_cast<uint16_t*>(plane_y); \
|
||||||
|
uint16_t* plane_u16 = reinterpret_cast<uint16_t*>(plane_u); \
|
||||||
|
uint16_t* plane_v16 = reinterpret_cast<uint16_t*>(plane_v); \
|
||||||
|
for (int i = 0; i < kPixels; ++i) { \
|
||||||
|
src_y16[i] = static_cast<uint16_t>((fastrand() & 0x3ff) << 6); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < kPixels * 2; ++i) { \
|
||||||
|
src_uv16[i] = static_cast<uint16_t>((fastrand() & 0x3ff) << 6); \
|
||||||
|
} \
|
||||||
|
EXPECT_EQ(0, FMT_BP##To##FMT_PLANAR(src_y16, kWidth, src_uv16, kWidth * 2, \
|
||||||
|
plane_y16, kWidth, plane_u16, kWidth, \
|
||||||
|
plane_v16, kWidth, kWidth, kHeight)); \
|
||||||
|
EXPECT_EQ(0, FMT_BP##ToARGBMatrix(src_y16, kWidth, src_uv16, kWidth * 2, \
|
||||||
|
dst_bp, kWidth * 4, &kYuvI601Constants, \
|
||||||
|
kWidth, kHeight)); \
|
||||||
|
EXPECT_EQ( \
|
||||||
|
0, FMT_PLANAR##ToARGBMatrix(plane_y16, kWidth, plane_u16, kWidth, \
|
||||||
|
plane_v16, kWidth, dst_planar, kWidth * 4, \
|
||||||
|
&kYuvI601Constants, kWidth, kHeight)); \
|
||||||
|
int max_diff = 0; \
|
||||||
|
for (int i = 0; i < kPixels * 4; ++i) { \
|
||||||
|
const int diff = Abs(dst_bp[i] - dst_planar[i]); \
|
||||||
|
if (diff > max_diff) { \
|
||||||
|
max_diff = diff; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
EXPECT_LE(max_diff, 1); \
|
||||||
|
free_aligned_buffer_page_end(src_y); \
|
||||||
|
free_aligned_buffer_page_end(src_uv); \
|
||||||
|
free_aligned_buffer_page_end(plane_y); \
|
||||||
|
free_aligned_buffer_page_end(plane_u); \
|
||||||
|
free_aligned_buffer_page_end(plane_v); \
|
||||||
|
free_aligned_buffer_page_end(dst_bp); \
|
||||||
|
free_aligned_buffer_page_end(dst_planar); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTBP16TOBTRANSITIVE(P010, I010)
|
||||||
|
TESTBP16TOBTRANSITIVE(P210, I210)
|
||||||
|
TESTBP16TOBTRANSITIVE(P410, I410)
|
||||||
|
|
||||||
#define TESTATOBI(FMT_A, TYPE_A, EPP_A, STRIDE_A, HEIGHT_A, FMT_B, TYPE_B, \
|
#define TESTATOBI(FMT_A, TYPE_A, EPP_A, STRIDE_A, HEIGHT_A, FMT_B, TYPE_B, \
|
||||||
EPP_B, STRIDE_B, HEIGHT_B, W1280, N, NEG, OFF) \
|
EPP_B, STRIDE_B, HEIGHT_B, W1280, N, NEG, OFF) \
|
||||||
TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) { \
|
TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) { \
|
||||||
@ -1686,41 +1745,82 @@ TEST_F(LibYUVConvertTest, RotateWithARGBSource) {
|
|||||||
ASSERT_EQ(dst[3], src[1]);
|
ASSERT_EQ(dst[3], src[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertToARGB_NV16) {
|
#define TESTCONVERTTOARGBSMOKE(FMT, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
const int kWidth = 64;
|
TEST_F(LibYUVConvertTest, ConvertToARGB_##FMT) { \
|
||||||
const int kHeight = 48;
|
const int kWidth = 64; \
|
||||||
const int sample_size = kWidth * kHeight * 2;
|
const int kHeight = 48; \
|
||||||
align_buffer_page_end(src, sample_size);
|
const int kUvStride = \
|
||||||
align_buffer_page_end(dst, kWidth * kHeight * 4);
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
MemRandomize(src, sample_size);
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
memset(dst, 0, kWidth * kHeight * 4);
|
const int kSampleSize = \
|
||||||
|
(kWidth * kHeight + kUvStride * kUvHeight) * BPC; \
|
||||||
|
align_buffer_page_end(src, kSampleSize); \
|
||||||
|
align_buffer_page_end(dst, kWidth * kHeight * 4); \
|
||||||
|
MemRandomize(src, kSampleSize); \
|
||||||
|
memset(dst, 0, kWidth * kHeight * 4); \
|
||||||
|
EXPECT_EQ(0, ConvertToARGB(src, kSampleSize, dst, kWidth * 4, 0, 0, \
|
||||||
|
kWidth, kHeight, kWidth, kHeight, kRotate0, \
|
||||||
|
FOURCC_##FMT)); \
|
||||||
|
free_aligned_buffer_page_end(src); \
|
||||||
|
free_aligned_buffer_page_end(dst); \
|
||||||
|
}
|
||||||
|
|
||||||
int r = ConvertToARGB(src, sample_size, dst, kWidth * 4,
|
TESTCONVERTTOARGBSMOKE(NV16, 1, 2, 1)
|
||||||
0, 0, kWidth, kHeight, kWidth, kHeight,
|
TESTCONVERTTOARGBSMOKE(NV24, 1, 1, 1)
|
||||||
kRotate0, FOURCC_NV16);
|
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src);
|
#define TESTCONVERTTOARGBI(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, W1280, N, \
|
||||||
free_aligned_buffer_page_end(dst);
|
NEG) \
|
||||||
}
|
TEST_F(LibYUVConvertTest, ConvertToARGB_##FMT##N) { \
|
||||||
|
const int kWidth = W1280; \
|
||||||
|
const int kHeight = benchmark_height_; \
|
||||||
|
const int kUvStride = \
|
||||||
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kYPixels = kWidth * kHeight; \
|
||||||
|
const int kUvPixels = kUvStride * kUvHeight; \
|
||||||
|
align_buffer_page_end(src, (kYPixels + kUvPixels) * BPC); \
|
||||||
|
align_buffer_page_end(dst, kWidth * kHeight * 4); \
|
||||||
|
align_buffer_page_end(ref, kWidth * kHeight * 4); \
|
||||||
|
TYPE* src_p = reinterpret_cast<TYPE*>(src); \
|
||||||
|
MemRandomize(src, (kYPixels + kUvPixels) * BPC); \
|
||||||
|
if (BPC == 2) { \
|
||||||
|
for (int i = 0; i < kYPixels + kUvPixels; ++i) { \
|
||||||
|
src_p[i] = static_cast<TYPE>(src_p[i] & 0xffc0); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
memset(dst, 1, kWidth * kHeight * 4); \
|
||||||
|
memset(ref, 2, kWidth * kHeight * 4); \
|
||||||
|
EXPECT_EQ(0, FMT##ToARGBMatrix(src_p, kWidth, src_p + kYPixels, kUvStride, \
|
||||||
|
ref, kWidth * 4, &kYuvI601Constants, \
|
||||||
|
kWidth, NEG kHeight)); \
|
||||||
|
EXPECT_EQ(0, ConvertToARGB(src, 0, dst, kWidth * 4, 0, 0, kWidth, \
|
||||||
|
NEG kHeight, kWidth, kHeight, kRotate0, \
|
||||||
|
FOURCC_##FMT)); \
|
||||||
|
for (int i = 0; i < kWidth * kHeight * 4; ++i) { \
|
||||||
|
ASSERT_EQ(dst[i], ref[i]); \
|
||||||
|
} \
|
||||||
|
free_aligned_buffer_page_end(src); \
|
||||||
|
free_aligned_buffer_page_end(dst); \
|
||||||
|
free_aligned_buffer_page_end(ref); \
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertToARGB_NV24) {
|
#if defined(ENABLE_FULL_TESTS)
|
||||||
const int kWidth = 64;
|
#define TESTCONVERTTOARGB(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
const int kHeight = 48;
|
TESTCONVERTTOARGBI(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
const int sample_size = kWidth * kHeight * 3;
|
benchmark_width_ + 1, _Any, +) \
|
||||||
align_buffer_page_end(src, sample_size);
|
TESTCONVERTTOARGBI(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
align_buffer_page_end(dst, kWidth * kHeight * 4);
|
benchmark_width_, _Invert, -) \
|
||||||
MemRandomize(src, sample_size);
|
TESTCONVERTTOARGBI(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
memset(dst, 0, kWidth * kHeight * 4);
|
benchmark_width_, _Opt, +)
|
||||||
|
#else
|
||||||
|
#define TESTCONVERTTOARGB(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TESTCONVERTTOARGBI(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Opt, +)
|
||||||
|
#endif
|
||||||
|
|
||||||
int r = ConvertToARGB(src, sample_size, dst, kWidth * 4,
|
TESTCONVERTTOARGB(P010, uint16_t, 2, 2, 2)
|
||||||
0, 0, kWidth, kHeight, kWidth, kHeight,
|
TESTCONVERTTOARGB(P210, uint16_t, 2, 2, 1)
|
||||||
kRotate0, FOURCC_NV24);
|
TESTCONVERTTOARGB(P410, uint16_t, 2, 1, 1)
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src);
|
|
||||||
free_aligned_buffer_page_end(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAS_ARGBTOAR30ROW_AVX2
|
#ifdef HAS_ARGBTOAR30ROW_AVX2
|
||||||
TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) {
|
TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) {
|
||||||
@ -2253,28 +2353,40 @@ TESTQPLANAR16TOB(I210Alpha, 2, 1, ARGBFilter, 4, 4, 1, 10)
|
|||||||
P010ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P010ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P210ToARGB(a, b, c, d, e, f, g, h) \
|
#define P210ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
P210ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P210ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P410ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
|
P410ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P010ToAR30(a, b, c, d, e, f, g, h) \
|
#define P010ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P010ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P010ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P210ToAR30(a, b, c, d, e, f, g, h) \
|
#define P210ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P210ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P210ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P410ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
|
P410ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
|
||||||
#define P012ToARGB(a, b, c, d, e, f, g, h) \
|
#define P012ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
P012ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P012ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P212ToARGB(a, b, c, d, e, f, g, h) \
|
#define P212ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
P212ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P212ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P412ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
|
P412ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P012ToAR30(a, b, c, d, e, f, g, h) \
|
#define P012ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P012ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P012ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P212ToAR30(a, b, c, d, e, f, g, h) \
|
#define P212ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P212ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P212ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P412ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
|
P412ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
|
||||||
#define P016ToARGB(a, b, c, d, e, f, g, h) \
|
#define P016ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
P016ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P016ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P216ToARGB(a, b, c, d, e, f, g, h) \
|
#define P216ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
P216ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P216ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P416ToARGB(a, b, c, d, e, f, g, h) \
|
||||||
|
P416ToARGBMatrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P016ToAR30(a, b, c, d, e, f, g, h) \
|
#define P016ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P016ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P016ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
#define P216ToAR30(a, b, c, d, e, f, g, h) \
|
#define P216ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
P216ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
P216ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
#define P416ToAR30(a, b, c, d, e, f, g, h) \
|
||||||
|
P416ToAR30Matrix(a, b, c, d, e, f, &kYuvH709Constants, g, h)
|
||||||
|
|
||||||
#define P010ToARGBFilter(a, b, c, d, e, f, g, h) \
|
#define P010ToARGBFilter(a, b, c, d, e, f, g, h) \
|
||||||
P010ToARGBMatrixFilter(a, b, c, d, e, f, &kYuvH709Constants, g, h, \
|
P010ToARGBMatrixFilter(a, b, c, d, e, f, &kYuvH709Constants, g, h, \
|
||||||
@ -2292,19 +2404,25 @@ TESTQPLANAR16TOB(I210Alpha, 2, 1, ARGBFilter, 4, 4, 1, 10)
|
|||||||
#if !defined(DISABLE_SLOW_TESTS) || defined(__x86_64__) || defined(__i386__)
|
#if !defined(DISABLE_SLOW_TESTS) || defined(__x86_64__) || defined(__i386__)
|
||||||
TESTBP16TOB(P010, 2, 2, ARGB, 4, 4, 1, 10)
|
TESTBP16TOB(P010, 2, 2, ARGB, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P210, 2, 1, ARGB, 4, 4, 1, 10)
|
TESTBP16TOB(P210, 2, 1, ARGB, 4, 4, 1, 10)
|
||||||
|
TESTBP16TOB(P410, 1, 1, ARGB, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P012, 2, 2, ARGB, 4, 4, 1, 12)
|
TESTBP16TOB(P012, 2, 2, ARGB, 4, 4, 1, 12)
|
||||||
TESTBP16TOB(P212, 2, 1, ARGB, 4, 4, 1, 12)
|
TESTBP16TOB(P212, 2, 1, ARGB, 4, 4, 1, 12)
|
||||||
|
TESTBP16TOB(P412, 1, 1, ARGB, 4, 4, 1, 12)
|
||||||
TESTBP16TOB(P016, 2, 2, ARGB, 4, 4, 1, 16)
|
TESTBP16TOB(P016, 2, 2, ARGB, 4, 4, 1, 16)
|
||||||
TESTBP16TOB(P216, 2, 1, ARGB, 4, 4, 1, 16)
|
TESTBP16TOB(P216, 2, 1, ARGB, 4, 4, 1, 16)
|
||||||
|
TESTBP16TOB(P416, 1, 1, ARGB, 4, 4, 1, 16)
|
||||||
TESTBP16TOB(P010, 2, 2, ARGBFilter, 4, 4, 1, 10)
|
TESTBP16TOB(P010, 2, 2, ARGBFilter, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P210, 2, 1, ARGBFilter, 4, 4, 1, 10)
|
TESTBP16TOB(P210, 2, 1, ARGBFilter, 4, 4, 1, 10)
|
||||||
#ifdef LITTLE_ENDIAN_ONLY_TEST
|
#ifdef LITTLE_ENDIAN_ONLY_TEST
|
||||||
TESTBP16TOB(P010, 2, 2, AR30, 4, 4, 1, 10)
|
TESTBP16TOB(P010, 2, 2, AR30, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P210, 2, 1, AR30, 4, 4, 1, 10)
|
TESTBP16TOB(P210, 2, 1, AR30, 4, 4, 1, 10)
|
||||||
|
TESTBP16TOB(P410, 1, 1, AR30, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P012, 2, 2, AR30, 4, 4, 1, 12)
|
TESTBP16TOB(P012, 2, 2, AR30, 4, 4, 1, 12)
|
||||||
TESTBP16TOB(P212, 2, 1, AR30, 4, 4, 1, 12)
|
TESTBP16TOB(P212, 2, 1, AR30, 4, 4, 1, 12)
|
||||||
|
TESTBP16TOB(P412, 1, 1, AR30, 4, 4, 1, 12)
|
||||||
TESTBP16TOB(P016, 2, 2, AR30, 4, 4, 1, 16)
|
TESTBP16TOB(P016, 2, 2, AR30, 4, 4, 1, 16)
|
||||||
TESTBP16TOB(P216, 2, 1, AR30, 4, 4, 1, 16)
|
TESTBP16TOB(P216, 2, 1, AR30, 4, 4, 1, 16)
|
||||||
|
TESTBP16TOB(P416, 1, 1, AR30, 4, 4, 1, 16)
|
||||||
TESTBP16TOB(P010, 2, 2, AR30Filter, 4, 4, 1, 10)
|
TESTBP16TOB(P010, 2, 2, AR30Filter, 4, 4, 1, 10)
|
||||||
TESTBP16TOB(P210, 2, 1, AR30Filter, 4, 4, 1, 10)
|
TESTBP16TOB(P210, 2, 1, AR30Filter, 4, 4, 1, 10)
|
||||||
#endif // LITTLE_ENDIAN_ONLY_TEST
|
#endif // LITTLE_ENDIAN_ONLY_TEST
|
||||||
|
|||||||
@ -463,6 +463,200 @@ TESTPLANARTOBP(I010, uint16_t, 2, 2, 2, P010, uint16_t, 2, 2, 2, 10)
|
|||||||
TESTPLANARTOBP(I210, uint16_t, 2, 2, 1, P210, uint16_t, 2, 2, 1, 10)
|
TESTPLANARTOBP(I210, uint16_t, 2, 2, 1, P210, uint16_t, 2, 2, 1, 10)
|
||||||
TESTPLANARTOBP(I012, uint16_t, 2, 2, 2, P012, uint16_t, 2, 2, 2, 12)
|
TESTPLANARTOBP(I012, uint16_t, 2, 2, 2, P012, uint16_t, 2, 2, 2, 12)
|
||||||
TESTPLANARTOBP(I212, uint16_t, 2, 2, 1, P212, uint16_t, 2, 2, 1, 12)
|
TESTPLANARTOBP(I212, uint16_t, 2, 2, 1, P212, uint16_t, 2, 2, 1, 12)
|
||||||
|
TESTPLANARTOBP(I420, uint8_t, 1, 2, 2, P010, uint16_t, 2, 2, 2, 8)
|
||||||
|
TESTPLANARTOBP(I422, uint8_t, 1, 2, 1, P210, uint16_t, 2, 2, 1, 8)
|
||||||
|
TESTPLANARTOBP(I444, uint8_t, 1, 1, 1, P410, uint16_t, 2, 1, 1, 8)
|
||||||
|
TESTPLANARTOBP(I420, uint8_t, 1, 2, 2, P210, uint16_t, 2, 2, 1, 8)
|
||||||
|
TESTPLANARTOBP(I420, uint8_t, 1, 2, 2, P410, uint16_t, 2, 1, 1, 8)
|
||||||
|
TESTPLANARTOBP(I410, uint16_t, 2, 1, 1, P410, uint16_t, 2, 1, 1, 10)
|
||||||
|
TESTPLANARTOBP(I412, uint16_t, 2, 1, 1, P412, uint16_t, 2, 1, 1, 12)
|
||||||
|
|
||||||
|
#define TESTCONVERTFROMI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, W1280, N, \
|
||||||
|
NEG) \
|
||||||
|
TEST_F(LibYUVConvertTest, ConvertFromI420_##FMT##N) { \
|
||||||
|
const int kWidth = W1280; \
|
||||||
|
const int kHeight = benchmark_height_; \
|
||||||
|
const int kHalfWidth = SUBSAMPLE(kWidth, 2); \
|
||||||
|
const int kHalfHeight = SUBSAMPLE(kHeight, 2); \
|
||||||
|
const int kUvStride = \
|
||||||
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kSamplePixels = kWidth * kHeight + kUvStride * kUvHeight; \
|
||||||
|
align_buffer_page_end(src_y, kWidth * kHeight); \
|
||||||
|
align_buffer_page_end(src_u, kHalfWidth * kHalfHeight); \
|
||||||
|
align_buffer_page_end(src_v, kHalfWidth * kHalfHeight); \
|
||||||
|
align_buffer_page_end(dst, kSamplePixels * BPC); \
|
||||||
|
align_buffer_page_end(ref, kSamplePixels * BPC); \
|
||||||
|
MemRandomize(src_y, kWidth * kHeight); \
|
||||||
|
MemRandomize(src_u, kHalfWidth * kHalfHeight); \
|
||||||
|
MemRandomize(src_v, kHalfWidth * kHalfHeight); \
|
||||||
|
memset(dst, 0, kSamplePixels * BPC); \
|
||||||
|
memset(ref, 1, kSamplePixels * BPC); \
|
||||||
|
TYPE* dst_p = reinterpret_cast<TYPE*>(dst); \
|
||||||
|
TYPE* ref_p = reinterpret_cast<TYPE*>(ref); \
|
||||||
|
EXPECT_EQ(0, I420To##FMT(src_y, kWidth, src_u, kHalfWidth, src_v, \
|
||||||
|
kHalfWidth, ref_p, kWidth, \
|
||||||
|
ref_p + kWidth * kHeight, kUvStride, kWidth, \
|
||||||
|
NEG kHeight)); \
|
||||||
|
EXPECT_EQ(0, ConvertFromI420(src_y, kWidth, src_u, kHalfWidth, src_v, \
|
||||||
|
kHalfWidth, dst, 0, kWidth, NEG kHeight, \
|
||||||
|
FOURCC_##FMT)); \
|
||||||
|
for (int i = 0; i < kSamplePixels; ++i) { \
|
||||||
|
ASSERT_EQ(dst_p[i], ref_p[i]); \
|
||||||
|
} \
|
||||||
|
if (BPC == 2) { \
|
||||||
|
EXPECT_EQ(-1, ConvertFromI420(src_y, kWidth, src_u, kHalfWidth, src_v, \
|
||||||
|
kHalfWidth, dst, 1, kWidth, kHeight, \
|
||||||
|
FOURCC_##FMT)); \
|
||||||
|
} \
|
||||||
|
free_aligned_buffer_page_end(src_y); \
|
||||||
|
free_aligned_buffer_page_end(src_u); \
|
||||||
|
free_aligned_buffer_page_end(src_v); \
|
||||||
|
free_aligned_buffer_page_end(dst); \
|
||||||
|
free_aligned_buffer_page_end(ref); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TESTCONVERTTOI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, W1280, N, \
|
||||||
|
NEG) \
|
||||||
|
TEST_F(LibYUVConvertTest, ConvertToI420_##FMT##N) { \
|
||||||
|
const int kWidth = W1280; \
|
||||||
|
const int kHeight = benchmark_height_; \
|
||||||
|
const int kHalfWidth = SUBSAMPLE(kWidth, 2); \
|
||||||
|
const int kHalfHeight = SUBSAMPLE(kHeight, 2); \
|
||||||
|
const int kUvStride = \
|
||||||
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kYPixels = kWidth * kHeight; \
|
||||||
|
const int kUvPixels = kUvStride * kUvHeight; \
|
||||||
|
align_buffer_page_end(src, (kYPixels + kUvPixels) * BPC); \
|
||||||
|
align_buffer_page_end(dst_y, kWidth * kHeight); \
|
||||||
|
align_buffer_page_end(dst_u, kHalfWidth * kHalfHeight); \
|
||||||
|
align_buffer_page_end(dst_v, kHalfWidth * kHalfHeight); \
|
||||||
|
align_buffer_page_end(ref_y, kWidth * kHeight); \
|
||||||
|
align_buffer_page_end(ref_u, kHalfWidth * kHalfHeight); \
|
||||||
|
align_buffer_page_end(ref_v, kHalfWidth * kHalfHeight); \
|
||||||
|
TYPE* src_p = reinterpret_cast<TYPE*>(src); \
|
||||||
|
MemRandomize(src, (kYPixels + kUvPixels) * BPC); \
|
||||||
|
if (BPC == 2) { \
|
||||||
|
for (int i = 0; i < kYPixels + kUvPixels; ++i) { \
|
||||||
|
src_p[i] = static_cast<TYPE>(src_p[i] & 0xffc0); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
memset(dst_y, 1, kWidth * kHeight); \
|
||||||
|
memset(dst_u, 2, kHalfWidth * kHalfHeight); \
|
||||||
|
memset(dst_v, 3, kHalfWidth * kHalfHeight); \
|
||||||
|
memset(ref_y, 4, kWidth * kHeight); \
|
||||||
|
memset(ref_u, 5, kHalfWidth * kHalfHeight); \
|
||||||
|
memset(ref_v, 6, kHalfWidth * kHalfHeight); \
|
||||||
|
EXPECT_EQ(0, FMT##ToI420(src_p, kWidth, src_p + kYPixels, kUvStride, \
|
||||||
|
ref_y, kWidth, ref_u, kHalfWidth, ref_v, \
|
||||||
|
kHalfWidth, kWidth, NEG kHeight)); \
|
||||||
|
EXPECT_EQ(0, ConvertToI420(src, 0, dst_y, kWidth, dst_u, kHalfWidth, \
|
||||||
|
dst_v, kHalfWidth, 0, 0, kWidth, NEG kHeight,\
|
||||||
|
kWidth, kHeight, kRotate0, FOURCC_##FMT)); \
|
||||||
|
for (int i = 0; i < kWidth * kHeight; ++i) { \
|
||||||
|
ASSERT_EQ(dst_y[i], ref_y[i]); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < kHalfWidth * kHalfHeight; ++i) { \
|
||||||
|
ASSERT_EQ(dst_u[i], ref_u[i]); \
|
||||||
|
ASSERT_EQ(dst_v[i], ref_v[i]); \
|
||||||
|
} \
|
||||||
|
free_aligned_buffer_page_end(src); \
|
||||||
|
free_aligned_buffer_page_end(dst_y); \
|
||||||
|
free_aligned_buffer_page_end(dst_u); \
|
||||||
|
free_aligned_buffer_page_end(dst_v); \
|
||||||
|
free_aligned_buffer_page_end(ref_y); \
|
||||||
|
free_aligned_buffer_page_end(ref_u); \
|
||||||
|
free_aligned_buffer_page_end(ref_v); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(ENABLE_FULL_TESTS)
|
||||||
|
#define TESTCONVERTFROMI420(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TESTCONVERTFROMI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_ + 1, _Any, +) \
|
||||||
|
TESTCONVERTFROMI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Invert, -) \
|
||||||
|
TESTCONVERTFROMI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Opt, +)
|
||||||
|
#define TESTCONVERTTOI420(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TESTCONVERTTOI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_ + 1, _Any, +) \
|
||||||
|
TESTCONVERTTOI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Invert, -) \
|
||||||
|
TESTCONVERTTOI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Opt, +)
|
||||||
|
#else
|
||||||
|
#define TESTCONVERTFROMI420(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TESTCONVERTFROMI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Opt, +)
|
||||||
|
#define TESTCONVERTTOI420(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TESTCONVERTTOI420I(FMT, TYPE, BPC, SUBSAMP_X, SUBSAMP_Y, \
|
||||||
|
benchmark_width_, _Opt, +)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TESTCONVERTFROMI420(P010, uint16_t, 2, 2, 2)
|
||||||
|
TESTCONVERTFROMI420(P210, uint16_t, 2, 2, 1)
|
||||||
|
TESTCONVERTFROMI420(P410, uint16_t, 2, 1, 1)
|
||||||
|
TESTCONVERTTOI420(P010, uint16_t, 2, 2, 2)
|
||||||
|
TESTCONVERTTOI420(P210, uint16_t, 2, 2, 1)
|
||||||
|
TESTCONVERTTOI420(P410, uint16_t, 2, 1, 1)
|
||||||
|
|
||||||
|
#define TESTCONVERTTOI420SMOKE(FMT, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TEST_F(LibYUVConvertTest, ConvertToI420_##FMT) { \
|
||||||
|
const int kWidth = 64; \
|
||||||
|
const int kHeight = 48; \
|
||||||
|
const int kUvStride = \
|
||||||
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kSampleSize = \
|
||||||
|
(kWidth * kHeight + kUvStride * kUvHeight) * BPC; \
|
||||||
|
align_buffer_page_end(src, kSampleSize); \
|
||||||
|
align_buffer_page_end(dst_y, kWidth * kHeight); \
|
||||||
|
align_buffer_page_end(dst_u, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
align_buffer_page_end(dst_v, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
MemRandomize(src, kSampleSize); \
|
||||||
|
memset(dst_y, 0, kWidth * kHeight); \
|
||||||
|
memset(dst_u, 0, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
memset(dst_v, 0, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
EXPECT_EQ(0, ConvertToI420(src, kSampleSize, dst_y, kWidth, dst_u, \
|
||||||
|
kWidth / 2, dst_v, kWidth / 2, 0, 0, kWidth, \
|
||||||
|
kHeight, kWidth, kHeight, kRotate0, \
|
||||||
|
FOURCC_##FMT)); \
|
||||||
|
free_aligned_buffer_page_end(src); \
|
||||||
|
free_aligned_buffer_page_end(dst_y); \
|
||||||
|
free_aligned_buffer_page_end(dst_u); \
|
||||||
|
free_aligned_buffer_page_end(dst_v); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TESTCONVERTFROMI420SMOKE(FMT, BPC, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TEST_F(LibYUVConvertTest, ConvertFromI420_##FMT) { \
|
||||||
|
const int kWidth = 64; \
|
||||||
|
const int kHeight = 48; \
|
||||||
|
const int kUvStride = \
|
||||||
|
(SUBSAMP_X == 1) ? kWidth * 2 : ((kWidth + 1) & ~1); \
|
||||||
|
const int kUvHeight = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kDstSize = (kWidth * kHeight + kUvStride * kUvHeight) * BPC; \
|
||||||
|
align_buffer_page_end(src_y, kWidth * kHeight); \
|
||||||
|
align_buffer_page_end(src_u, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
align_buffer_page_end(src_v, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
align_buffer_page_end(dst, kDstSize); \
|
||||||
|
MemRandomize(src_y, kWidth * kHeight); \
|
||||||
|
MemRandomize(src_u, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
MemRandomize(src_v, (kWidth / 2) * (kHeight / 2)); \
|
||||||
|
memset(dst, 0, kDstSize); \
|
||||||
|
EXPECT_EQ(0, ConvertFromI420(src_y, kWidth, src_u, kWidth / 2, src_v, \
|
||||||
|
kWidth / 2, dst, kWidth * BPC, kWidth, \
|
||||||
|
kHeight, FOURCC_##FMT)); \
|
||||||
|
free_aligned_buffer_page_end(src_y); \
|
||||||
|
free_aligned_buffer_page_end(src_u); \
|
||||||
|
free_aligned_buffer_page_end(src_v); \
|
||||||
|
free_aligned_buffer_page_end(dst); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTCONVERTTOI420SMOKE(NV16, 1, 2, 1)
|
||||||
|
TESTCONVERTTOI420SMOKE(NV24, 1, 1, 1)
|
||||||
|
TESTCONVERTFROMI420SMOKE(NV16, 1, 2, 1)
|
||||||
|
TESTCONVERTFROMI420SMOKE(NV24, 1, 1, 1)
|
||||||
|
|
||||||
#define TESTBPTOBPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \
|
#define TESTBPTOBPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \
|
||||||
SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, \
|
SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, \
|
||||||
@ -1039,6 +1233,62 @@ TESTATOBP16FROM8(ARGB, P010, NV12, 2, 2)
|
|||||||
TESTATOBP16FROM8(ARGB, P210, NV16, 2, 1)
|
TESTATOBP16FROM8(ARGB, P210, NV16, 2, 1)
|
||||||
TESTATOBP16FROM8(ARGB, P410, NV24, 1, 1)
|
TESTATOBP16FROM8(ARGB, P410, NV24, 1, 1)
|
||||||
|
|
||||||
|
#define TESTATOBP16TRANSITIVE(FMT_A, FMT_I, FMT_P, SUBSAMP_X, SUBSAMP_Y) \
|
||||||
|
TEST_F(LibYUVConvertTest, Test##FMT_A##To##FMT_P##Transitive) { \
|
||||||
|
const int kWidth = benchmark_width_ | 1; \
|
||||||
|
const int kHeight = benchmark_height_; \
|
||||||
|
const int kWidthUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
|
||||||
|
const int kHeightUV = SUBSAMPLE(kHeight, SUBSAMP_Y); \
|
||||||
|
const int kYSize = kWidth * kHeight; \
|
||||||
|
const int kUVSize = kWidthUV * kHeightUV; \
|
||||||
|
align_buffer_page_end(src_argb, kYSize * 4); \
|
||||||
|
align_buffer_page_end(dst_p_y, kYSize * 2); \
|
||||||
|
align_buffer_page_end(dst_p_uv, kUVSize * 2 * 2); \
|
||||||
|
align_buffer_page_end(ref_y, kYSize); \
|
||||||
|
align_buffer_page_end(ref_u, kUVSize); \
|
||||||
|
align_buffer_page_end(ref_v, kUVSize); \
|
||||||
|
align_buffer_page_end(ref_p_y, kYSize * 2); \
|
||||||
|
align_buffer_page_end(ref_p_uv, kUVSize * 2 * 2); \
|
||||||
|
uint16_t* dst_p_y16 = reinterpret_cast<uint16_t*>(dst_p_y); \
|
||||||
|
uint16_t* dst_p_uv16 = reinterpret_cast<uint16_t*>(dst_p_uv); \
|
||||||
|
uint16_t* ref_p_y16 = reinterpret_cast<uint16_t*>(ref_p_y); \
|
||||||
|
uint16_t* ref_p_uv16 = reinterpret_cast<uint16_t*>(ref_p_uv); \
|
||||||
|
MemRandomize(src_argb, kYSize * 4); \
|
||||||
|
memset(dst_p_y, 1, kYSize * 2); \
|
||||||
|
memset(dst_p_uv, 2, kUVSize * 2 * 2); \
|
||||||
|
memset(ref_y, 3, kYSize); \
|
||||||
|
memset(ref_u, 4, kUVSize); \
|
||||||
|
memset(ref_v, 5, kUVSize); \
|
||||||
|
memset(ref_p_y, 6, kYSize * 2); \
|
||||||
|
memset(ref_p_uv, 7, kUVSize * 2 * 2); \
|
||||||
|
EXPECT_EQ(0, FMT_A##To##FMT_P(src_argb, kWidth * 4, dst_p_y16, kWidth, \
|
||||||
|
dst_p_uv16, kWidthUV * 2, kWidth, kHeight)); \
|
||||||
|
EXPECT_EQ(0, \
|
||||||
|
FMT_A##To##FMT_I(src_argb, kWidth * 4, ref_y, kWidth, ref_u, \
|
||||||
|
kWidthUV, ref_v, kWidthUV, kWidth, kHeight)); \
|
||||||
|
EXPECT_EQ(0, FMT_I##To##FMT_P(ref_y, kWidth, ref_u, kWidthUV, ref_v, \
|
||||||
|
kWidthUV, ref_p_y16, kWidth, ref_p_uv16, \
|
||||||
|
kWidthUV * 2, kWidth, kHeight)); \
|
||||||
|
for (int i = 0; i < kYSize; ++i) { \
|
||||||
|
ASSERT_EQ(dst_p_y16[i], ref_p_y16[i]); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < kUVSize * 2; ++i) { \
|
||||||
|
ASSERT_EQ(dst_p_uv16[i], ref_p_uv16[i]); \
|
||||||
|
} \
|
||||||
|
free_aligned_buffer_page_end(src_argb); \
|
||||||
|
free_aligned_buffer_page_end(dst_p_y); \
|
||||||
|
free_aligned_buffer_page_end(dst_p_uv); \
|
||||||
|
free_aligned_buffer_page_end(ref_y); \
|
||||||
|
free_aligned_buffer_page_end(ref_u); \
|
||||||
|
free_aligned_buffer_page_end(ref_v); \
|
||||||
|
free_aligned_buffer_page_end(ref_p_y); \
|
||||||
|
free_aligned_buffer_page_end(ref_p_uv); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTATOBP16TRANSITIVE(ARGB, I420, P010, 2, 2)
|
||||||
|
TESTATOBP16TRANSITIVE(ARGB, I422, P210, 2, 1)
|
||||||
|
TESTATOBP16TRANSITIVE(ARGB, I444, P410, 1, 1)
|
||||||
|
|
||||||
#if !defined(LEAN_TESTS)
|
#if !defined(LEAN_TESTS)
|
||||||
|
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG
|
||||||
@ -2081,100 +2331,6 @@ TEST_F(LibYUVConvertTest, NV12Crop) {
|
|||||||
free_aligned_buffer_page_end(src_y);
|
free_aligned_buffer_page_end(src_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertToI420_NV16) {
|
|
||||||
const int kWidth = 64;
|
|
||||||
const int kHeight = 48;
|
|
||||||
const int sample_size = kWidth * kHeight * 2;
|
|
||||||
align_buffer_page_end(src, sample_size);
|
|
||||||
align_buffer_page_end(dst_y, kWidth * kHeight);
|
|
||||||
align_buffer_page_end(dst_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(dst_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
MemRandomize(src, sample_size);
|
|
||||||
memset(dst_y, 0, kWidth * kHeight);
|
|
||||||
memset(dst_u, 0, (kWidth / 2) * (kHeight / 2));
|
|
||||||
memset(dst_v, 0, (kWidth / 2) * (kHeight / 2));
|
|
||||||
|
|
||||||
int r = ConvertToI420(src, sample_size, dst_y, kWidth, dst_u, kWidth / 2,
|
|
||||||
dst_v, kWidth / 2, 0, 0, kWidth, kHeight, kWidth,
|
|
||||||
kHeight, kRotate0, FOURCC_NV16);
|
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src);
|
|
||||||
free_aligned_buffer_page_end(dst_y);
|
|
||||||
free_aligned_buffer_page_end(dst_u);
|
|
||||||
free_aligned_buffer_page_end(dst_v);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertToI420_NV24) {
|
|
||||||
const int kWidth = 64;
|
|
||||||
const int kHeight = 48;
|
|
||||||
const int sample_size = kWidth * kHeight * 3;
|
|
||||||
align_buffer_page_end(src, sample_size);
|
|
||||||
align_buffer_page_end(dst_y, kWidth * kHeight);
|
|
||||||
align_buffer_page_end(dst_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(dst_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
MemRandomize(src, sample_size);
|
|
||||||
memset(dst_y, 0, kWidth * kHeight);
|
|
||||||
memset(dst_u, 0, (kWidth / 2) * (kHeight / 2));
|
|
||||||
memset(dst_v, 0, (kWidth / 2) * (kHeight / 2));
|
|
||||||
|
|
||||||
int r = ConvertToI420(src, sample_size, dst_y, kWidth, dst_u, kWidth / 2,
|
|
||||||
dst_v, kWidth / 2, 0, 0, kWidth, kHeight, kWidth,
|
|
||||||
kHeight, kRotate0, FOURCC_NV24);
|
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src);
|
|
||||||
free_aligned_buffer_page_end(dst_y);
|
|
||||||
free_aligned_buffer_page_end(dst_u);
|
|
||||||
free_aligned_buffer_page_end(dst_v);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertFromI420_NV16) {
|
|
||||||
const int kWidth = 64;
|
|
||||||
const int kHeight = 48;
|
|
||||||
const int dst_size = kWidth * kHeight * 2;
|
|
||||||
align_buffer_page_end(src_y, kWidth * kHeight);
|
|
||||||
align_buffer_page_end(src_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(src_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(dst, dst_size);
|
|
||||||
MemRandomize(src_y, kWidth * kHeight);
|
|
||||||
MemRandomize(src_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
MemRandomize(src_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
memset(dst, 0, dst_size);
|
|
||||||
|
|
||||||
int r = ConvertFromI420(src_y, kWidth, src_u, kWidth / 2, src_v, kWidth / 2,
|
|
||||||
dst, kWidth, kWidth, kHeight, FOURCC_NV16);
|
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src_y);
|
|
||||||
free_aligned_buffer_page_end(src_u);
|
|
||||||
free_aligned_buffer_page_end(src_v);
|
|
||||||
free_aligned_buffer_page_end(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, ConvertFromI420_NV24) {
|
|
||||||
const int kWidth = 64;
|
|
||||||
const int kHeight = 48;
|
|
||||||
const int dst_size = kWidth * kHeight * 3;
|
|
||||||
align_buffer_page_end(src_y, kWidth * kHeight);
|
|
||||||
align_buffer_page_end(src_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(src_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
align_buffer_page_end(dst, dst_size);
|
|
||||||
MemRandomize(src_y, kWidth * kHeight);
|
|
||||||
MemRandomize(src_u, (kWidth / 2) * (kHeight / 2));
|
|
||||||
MemRandomize(src_v, (kWidth / 2) * (kHeight / 2));
|
|
||||||
memset(dst, 0, dst_size);
|
|
||||||
|
|
||||||
int r = ConvertFromI420(src_y, kWidth, src_u, kWidth / 2, src_v, kWidth / 2,
|
|
||||||
dst, kWidth, kWidth, kHeight, FOURCC_NV24);
|
|
||||||
EXPECT_EQ(0, r);
|
|
||||||
|
|
||||||
free_aligned_buffer_page_end(src_y);
|
|
||||||
free_aligned_buffer_page_end(src_u);
|
|
||||||
free_aligned_buffer_page_end(src_v);
|
|
||||||
free_aligned_buffer_page_end(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LibYUVConvertTest, I420CropOddY) {
|
TEST_F(LibYUVConvertTest, I420CropOddY) {
|
||||||
const int SUBSAMP_X = 2;
|
const int SUBSAMP_X = 2;
|
||||||
const int SUBSAMP_Y = 2;
|
const int SUBSAMP_Y = 2;
|
||||||
|
|||||||
@ -740,11 +740,26 @@ static int I444TestFilter_16(int src_width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
|
// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
|
||||||
static int NV12TestFilter(int src_width,
|
static int NVTestFilter(int src_width,
|
||||||
int src_height,
|
int src_height,
|
||||||
int dst_width,
|
int dst_width,
|
||||||
int dst_height,
|
int dst_height,
|
||||||
FilterMode f,
|
FilterMode f,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y,
|
||||||
|
int (*NVScale)(const uint8_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint8_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint8_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint8_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering),
|
||||||
int benchmark_iterations,
|
int benchmark_iterations,
|
||||||
int disable_cpu_flags,
|
int disable_cpu_flags,
|
||||||
int benchmark_cpu_info) {
|
int benchmark_cpu_info) {
|
||||||
@ -753,8 +768,9 @@ static int NV12TestFilter(int src_width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
int src_width_uv = (Abs(src_width) + 1) >> 1;
|
int src_width_uv = subsample_x ? ((Abs(src_width) + 1) >> 1) : Abs(src_width);
|
||||||
int src_height_uv = (Abs(src_height) + 1) >> 1;
|
int src_height_uv =
|
||||||
|
subsample_y ? ((Abs(src_height) + 1) >> 1) : Abs(src_height);
|
||||||
|
|
||||||
int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height));
|
int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height));
|
||||||
int64_t src_uv_plane_size = (src_width_uv) * (src_height_uv) * 2;
|
int64_t src_uv_plane_size = (src_width_uv) * (src_height_uv) * 2;
|
||||||
@ -771,8 +787,8 @@ static int NV12TestFilter(int src_width,
|
|||||||
MemRandomize(src_y, src_y_plane_size);
|
MemRandomize(src_y, src_y_plane_size);
|
||||||
MemRandomize(src_uv, src_uv_plane_size);
|
MemRandomize(src_uv, src_uv_plane_size);
|
||||||
|
|
||||||
int dst_width_uv = (dst_width + 1) >> 1;
|
int dst_width_uv = subsample_x ? ((dst_width + 1) >> 1) : dst_width;
|
||||||
int dst_height_uv = (dst_height + 1) >> 1;
|
int dst_height_uv = subsample_y ? ((dst_height + 1) >> 1) : dst_height;
|
||||||
|
|
||||||
int64_t dst_y_plane_size = (dst_width) * (dst_height);
|
int64_t dst_y_plane_size = (dst_width) * (dst_height);
|
||||||
int64_t dst_uv_plane_size = (dst_width_uv) * (dst_height_uv) * 2;
|
int64_t dst_uv_plane_size = (dst_width_uv) * (dst_height_uv) * 2;
|
||||||
@ -791,15 +807,15 @@ static int NV12TestFilter(int src_width,
|
|||||||
|
|
||||||
MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
|
MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
|
||||||
double c_time = get_time();
|
double c_time = get_time();
|
||||||
NV12Scale(src_y, src_stride_y, src_uv, src_stride_uv, src_width, src_height,
|
NVScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width, src_height,
|
||||||
dst_y_c, dst_stride_y, dst_uv_c, dst_stride_uv, dst_width,
|
dst_y_c, dst_stride_y, dst_uv_c, dst_stride_uv, dst_width, dst_height,
|
||||||
dst_height, f);
|
f);
|
||||||
c_time = (get_time() - c_time);
|
c_time = (get_time() - c_time);
|
||||||
|
|
||||||
MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
|
MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
|
||||||
double opt_time = get_time();
|
double opt_time = get_time();
|
||||||
for (i = 0; i < benchmark_iterations; ++i) {
|
for (i = 0; i < benchmark_iterations; ++i) {
|
||||||
NV12Scale(src_y, src_stride_y, src_uv, src_stride_uv, src_width, src_height,
|
NVScale(src_y, src_stride_y, src_uv, src_stride_uv, src_width, src_height,
|
||||||
dst_y_opt, dst_stride_y, dst_uv_opt, dst_stride_uv, dst_width,
|
dst_y_opt, dst_stride_y, dst_uv_opt, dst_stride_uv, dst_width,
|
||||||
dst_height, f);
|
dst_height, f);
|
||||||
}
|
}
|
||||||
@ -843,6 +859,219 @@ static int NV12TestFilter(int src_width,
|
|||||||
return max_diff;
|
return max_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int NV12TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return NVTestFilter(src_width, src_height, dst_width, dst_height, f, 1, 1,
|
||||||
|
NV12Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int NV16TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return NVTestFilter(src_width, src_height, dst_width, dst_height, f, 1, 0,
|
||||||
|
NV16Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int NV24TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return NVTestFilter(src_width, src_height, dst_width, dst_height, f, 0, 0,
|
||||||
|
NV24Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PxxxTestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int subsample_x,
|
||||||
|
int subsample_y,
|
||||||
|
int (*PxxxScale)(const uint16_t* src_y,
|
||||||
|
int src_stride_y,
|
||||||
|
const uint16_t* src_uv,
|
||||||
|
int src_stride_uv,
|
||||||
|
int src_width,
|
||||||
|
int src_height,
|
||||||
|
uint16_t* dst_y,
|
||||||
|
int dst_stride_y,
|
||||||
|
uint16_t* dst_uv,
|
||||||
|
int dst_stride_uv,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
enum FilterMode filtering),
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
if (!SizeValid(src_width, src_height, dst_width, dst_height)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
int src_width_uv = subsample_x ? ((Abs(src_width) + 1) >> 1) : Abs(src_width);
|
||||||
|
int src_height_uv =
|
||||||
|
subsample_y ? ((Abs(src_height) + 1) >> 1) : Abs(src_height);
|
||||||
|
|
||||||
|
int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height));
|
||||||
|
int64_t src_uv_plane_size = (src_width_uv) * (src_height_uv) * 2;
|
||||||
|
|
||||||
|
int src_stride_y = Abs(src_width);
|
||||||
|
int src_stride_uv = src_width_uv * 2;
|
||||||
|
|
||||||
|
align_buffer_page_end(src_y, src_y_plane_size * 2);
|
||||||
|
align_buffer_page_end(src_uv, src_uv_plane_size * 2);
|
||||||
|
if (!src_y || !src_uv) {
|
||||||
|
printf("Skipped. Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint16_t* p_src_y = reinterpret_cast<uint16_t*>(src_y);
|
||||||
|
uint16_t* p_src_uv = reinterpret_cast<uint16_t*>(src_uv);
|
||||||
|
MemRandomize(src_y, src_y_plane_size * 2);
|
||||||
|
MemRandomize(src_uv, src_uv_plane_size * 2);
|
||||||
|
for (i = 0; i < src_y_plane_size; ++i) {
|
||||||
|
p_src_y[i] = static_cast<uint16_t>(p_src_y[i] & 0xffc0);
|
||||||
|
}
|
||||||
|
for (i = 0; i < src_uv_plane_size; ++i) {
|
||||||
|
p_src_uv[i] = static_cast<uint16_t>(p_src_uv[i] & 0xffc0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_width_uv = subsample_x ? ((dst_width + 1) >> 1) : dst_width;
|
||||||
|
int dst_height_uv = subsample_y ? ((dst_height + 1) >> 1) : dst_height;
|
||||||
|
|
||||||
|
int64_t dst_y_plane_size = (dst_width) * (dst_height);
|
||||||
|
int64_t dst_uv_plane_size = (dst_width_uv) * (dst_height_uv) * 2;
|
||||||
|
|
||||||
|
int dst_stride_y = dst_width;
|
||||||
|
int dst_stride_uv = dst_width_uv * 2;
|
||||||
|
|
||||||
|
align_buffer_page_end(dst_y_c, dst_y_plane_size * 2);
|
||||||
|
align_buffer_page_end(dst_uv_c, dst_uv_plane_size * 2);
|
||||||
|
align_buffer_page_end(dst_y_opt, dst_y_plane_size * 2);
|
||||||
|
align_buffer_page_end(dst_uv_opt, dst_uv_plane_size * 2);
|
||||||
|
if (!dst_y_c || !dst_uv_c || !dst_y_opt || !dst_uv_opt) {
|
||||||
|
printf("Skipped. Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint16_t* p_dst_y_c = reinterpret_cast<uint16_t*>(dst_y_c);
|
||||||
|
uint16_t* p_dst_uv_c = reinterpret_cast<uint16_t*>(dst_uv_c);
|
||||||
|
uint16_t* p_dst_y_opt = reinterpret_cast<uint16_t*>(dst_y_opt);
|
||||||
|
uint16_t* p_dst_uv_opt = reinterpret_cast<uint16_t*>(dst_uv_opt);
|
||||||
|
|
||||||
|
MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
|
||||||
|
double c_time = get_time();
|
||||||
|
PxxxScale(p_src_y, src_stride_y, p_src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, p_dst_y_c, dst_stride_y, p_dst_uv_c, dst_stride_uv,
|
||||||
|
dst_width, dst_height, f);
|
||||||
|
c_time = (get_time() - c_time);
|
||||||
|
|
||||||
|
MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
|
||||||
|
double opt_time = get_time();
|
||||||
|
for (i = 0; i < benchmark_iterations; ++i) {
|
||||||
|
PxxxScale(p_src_y, src_stride_y, p_src_uv, src_stride_uv, src_width,
|
||||||
|
src_height, p_dst_y_opt, dst_stride_y, p_dst_uv_opt,
|
||||||
|
dst_stride_uv, dst_width, dst_height, f);
|
||||||
|
}
|
||||||
|
opt_time = (get_time() - opt_time) / benchmark_iterations;
|
||||||
|
printf("filter %d - %8d us C - %8d us OPT\n", f,
|
||||||
|
static_cast<int>(c_time * 1e6), static_cast<int>(opt_time * 1e6));
|
||||||
|
|
||||||
|
int max_diff = 0;
|
||||||
|
for (i = 0; i < dst_height; ++i) {
|
||||||
|
for (j = 0; j < dst_width; ++j) {
|
||||||
|
uint16_t c = p_dst_y_c[(i * dst_stride_y) + j];
|
||||||
|
uint16_t opt = p_dst_y_opt[(i * dst_stride_y) + j];
|
||||||
|
// Scaled output is converted back to canonical 10-bit MSB.
|
||||||
|
if ((c & 0x3f) || (opt & 0x3f)) {
|
||||||
|
max_diff = 999;
|
||||||
|
}
|
||||||
|
int abs_diff = Abs((c >> 6) - (opt >> 6));
|
||||||
|
if (abs_diff > max_diff) {
|
||||||
|
max_diff = abs_diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < dst_height_uv; ++i) {
|
||||||
|
for (j = 0; j < (dst_width_uv * 2); ++j) {
|
||||||
|
uint16_t c = p_dst_uv_c[(i * dst_stride_uv) + j];
|
||||||
|
uint16_t opt = p_dst_uv_opt[(i * dst_stride_uv) + j];
|
||||||
|
// MergeUVPlane_16 depth=10 must produce canonical 10-bit MSB samples.
|
||||||
|
if ((c & 0x3f) || (opt & 0x3f)) {
|
||||||
|
max_diff = 999;
|
||||||
|
}
|
||||||
|
int abs_diff = Abs((c >> 6) - (opt >> 6));
|
||||||
|
if (abs_diff > max_diff) {
|
||||||
|
max_diff = abs_diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_aligned_buffer_page_end(dst_y_c);
|
||||||
|
free_aligned_buffer_page_end(dst_uv_c);
|
||||||
|
free_aligned_buffer_page_end(dst_y_opt);
|
||||||
|
free_aligned_buffer_page_end(dst_uv_opt);
|
||||||
|
free_aligned_buffer_page_end(src_y);
|
||||||
|
free_aligned_buffer_page_end(src_uv);
|
||||||
|
|
||||||
|
return max_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int P010TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return PxxxTestFilter(src_width, src_height, dst_width, dst_height, f, 1, 1,
|
||||||
|
P010Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int P210TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return PxxxTestFilter(src_width, src_height, dst_width, dst_height, f, 1, 0,
|
||||||
|
P210Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int P410TestFilter(int src_width,
|
||||||
|
int src_height,
|
||||||
|
int dst_width,
|
||||||
|
int dst_height,
|
||||||
|
FilterMode f,
|
||||||
|
int benchmark_iterations,
|
||||||
|
int disable_cpu_flags,
|
||||||
|
int benchmark_cpu_info) {
|
||||||
|
return PxxxTestFilter(src_width, src_height, dst_width, dst_height, f, 0, 0,
|
||||||
|
P410Scale, benchmark_iterations, disable_cpu_flags,
|
||||||
|
benchmark_cpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
// The following adjustments in dimensions ensure the scale factor will be
|
// The following adjustments in dimensions ensure the scale factor will be
|
||||||
// exactly achieved.
|
// exactly achieved.
|
||||||
// 2 is chroma subsample.
|
// 2 is chroma subsample.
|
||||||
@ -889,6 +1118,46 @@ static int NV12TestFilter(int src_width,
|
|||||||
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
benchmark_cpu_info_); \
|
benchmark_cpu_info_); \
|
||||||
ASSERT_LE(diff, max_diff); \
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV16ScaleDownBy##name##_##filter) { \
|
||||||
|
int diff = NV16TestFilter( \
|
||||||
|
SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
|
||||||
|
DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
|
||||||
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV24ScaleDownBy##name##_##filter) { \
|
||||||
|
int diff = NV24TestFilter( \
|
||||||
|
SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
|
||||||
|
DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
|
||||||
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P010ScaleDownBy##name##_##filter) { \
|
||||||
|
int diff = P010TestFilter( \
|
||||||
|
SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
|
||||||
|
DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
|
||||||
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P210ScaleDownBy##name##_##filter) { \
|
||||||
|
int diff = P210TestFilter( \
|
||||||
|
SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
|
||||||
|
DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
|
||||||
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P410ScaleDownBy##name##_##filter) { \
|
||||||
|
int diff = P410TestFilter( \
|
||||||
|
SX(benchmark_width_, nom, denom), SX(benchmark_height_, nom, denom), \
|
||||||
|
DX(benchmark_width_, nom, denom), DX(benchmark_height_, nom, denom), \
|
||||||
|
kFilter##filter, benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test a scale factor with all 4 filters. Expect unfiltered to be exact, but
|
// Test a scale factor with all 4 filters. Expect unfiltered to be exact, but
|
||||||
@ -973,6 +1242,36 @@ TEST_FACTOR(3, 1, 3, 0)
|
|||||||
disable_cpu_flags_, benchmark_cpu_info_); \
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
ASSERT_LE(diff, max_diff); \
|
ASSERT_LE(diff, max_diff); \
|
||||||
} \
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV16##name##To##width##x##height##_##filter) { \
|
||||||
|
int diff = NV16TestFilter(benchmark_width_, benchmark_height_, width, \
|
||||||
|
height, kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV24##name##To##width##x##height##_##filter) { \
|
||||||
|
int diff = NV24TestFilter(benchmark_width_, benchmark_height_, width, \
|
||||||
|
height, kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P010##name##To##width##x##height##_##filter) { \
|
||||||
|
int diff = P010TestFilter(benchmark_width_, benchmark_height_, width, \
|
||||||
|
height, kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P210##name##To##width##x##height##_##filter) { \
|
||||||
|
int diff = P210TestFilter(benchmark_width_, benchmark_height_, width, \
|
||||||
|
height, kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P410##name##To##width##x##height##_##filter) { \
|
||||||
|
int diff = P410TestFilter(benchmark_width_, benchmark_height_, width, \
|
||||||
|
height, kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
TEST_F(LibYUVScaleTest, I420##name##From##width##x##height##_##filter) { \
|
TEST_F(LibYUVScaleTest, I420##name##From##width##x##height##_##filter) { \
|
||||||
int diff = I420TestFilter(width, height, Abs(benchmark_width_), \
|
int diff = I420TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
Abs(benchmark_height_), kFilter##filter, \
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
@ -1025,6 +1324,41 @@ TEST_FACTOR(3, 1, 3, 0)
|
|||||||
benchmark_iterations_, disable_cpu_flags_, \
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
benchmark_cpu_info_); \
|
benchmark_cpu_info_); \
|
||||||
ASSERT_LE(diff, max_diff); \
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV16##name##From##width##x##height##_##filter) { \
|
||||||
|
int diff = NV16TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV24##name##From##width##x##height##_##filter) { \
|
||||||
|
int diff = NV24TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P010##name##From##width##x##height##_##filter) { \
|
||||||
|
int diff = P010TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P210##name##From##width##x##height##_##filter) { \
|
||||||
|
int diff = P210TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P410##name##From##width##x##height##_##filter) { \
|
||||||
|
int diff = P410TestFilter(width, height, Abs(benchmark_width_), \
|
||||||
|
Abs(benchmark_height_), kFilter##filter, \
|
||||||
|
benchmark_iterations_, disable_cpu_flags_, \
|
||||||
|
benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_SLOW_TESTS
|
#ifndef DISABLE_SLOW_TESTS
|
||||||
@ -1111,6 +1445,41 @@ TEST_SCALETO(Scale, 1080, 1920) // for rotated phones
|
|||||||
kFilter##filter, benchmark_iterations_, \
|
kFilter##filter, benchmark_iterations_, \
|
||||||
disable_cpu_flags_, benchmark_cpu_info_); \
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
ASSERT_LE(diff, max_diff); \
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV16##name##SwapXY_##filter) { \
|
||||||
|
int diff = NV16TestFilter(benchmark_width_, benchmark_height_, \
|
||||||
|
benchmark_height_, benchmark_width_, \
|
||||||
|
kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, NV24##name##SwapXY_##filter) { \
|
||||||
|
int diff = NV24TestFilter(benchmark_width_, benchmark_height_, \
|
||||||
|
benchmark_height_, benchmark_width_, \
|
||||||
|
kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P010##name##SwapXY_##filter) { \
|
||||||
|
int diff = P010TestFilter(benchmark_width_, benchmark_height_, \
|
||||||
|
benchmark_height_, benchmark_width_, \
|
||||||
|
kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P210##name##SwapXY_##filter) { \
|
||||||
|
int diff = P210TestFilter(benchmark_width_, benchmark_height_, \
|
||||||
|
benchmark_height_, benchmark_width_, \
|
||||||
|
kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
|
} \
|
||||||
|
TEST_F(LibYUVScaleTest, P410##name##SwapXY_##filter) { \
|
||||||
|
int diff = P410TestFilter(benchmark_width_, benchmark_height_, \
|
||||||
|
benchmark_height_, benchmark_width_, \
|
||||||
|
kFilter##filter, benchmark_iterations_, \
|
||||||
|
disable_cpu_flags_, benchmark_cpu_info_); \
|
||||||
|
ASSERT_LE(diff, max_diff); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test scale to a specified size with all 4 filters.
|
// Test scale to a specified size with all 4 filters.
|
||||||
|
|||||||
@ -90,6 +90,7 @@ TEST_F(LibYUVBaseTest, TestFourCC) {
|
|||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_I210, FOURCC_BPP_I210));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_I210, FOURCC_BPP_I210));
|
||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_P010, FOURCC_BPP_P010));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_P010, FOURCC_BPP_P010));
|
||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_P210, FOURCC_BPP_P210));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_P210, FOURCC_BPP_P210));
|
||||||
|
ASSERT_TRUE(TestValidFourCC(FOURCC_P410, FOURCC_BPP_P410));
|
||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_MJPG, FOURCC_BPP_MJPG));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_MJPG, FOURCC_BPP_MJPG));
|
||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_YV12, FOURCC_BPP_YV12));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_YV12, FOURCC_BPP_YV12));
|
||||||
ASSERT_TRUE(TestValidFourCC(FOURCC_YV16, FOURCC_BPP_YV16));
|
ASSERT_TRUE(TestValidFourCC(FOURCC_YV16, FOURCC_BPP_YV16));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user