blob: b9a37138099e1ef8ffb03b45e490f0a7944892a1 [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Encoding from and to custom color space test.
#include <string>
#include <tuple>
#include "extras/extras.h"
#include "imageio/image_dec.h"
#include "include/helpers.h"
#include "src/utils/plane.h"
#include "src/wp2/decode.h"
#include "src/wp2/encode.h"
namespace WP2 {
namespace {
//------------------------------------------------------------------------------
// Matrices and associated shifts from extras.h
enum class Matrix { kRGB8, kRGB10, kYCoCg, kYpUV };
constexpr const int16_t* const kCCSPToRGBMatrices[] = {
kRGB8ToRGBMatrix, kRGB10ToRGBMatrix, kYCoCgToRGBMatrix, kYpUVToRGBMatrix};
constexpr const uint32_t kCCSPToRGBShifts[] = {
kRGB8ToRGBShift, kRGB10ToRGBShift, kYCoCgToRGBShift, kYpUVToRGBShift};
constexpr const int16_t* const kRGBToCCSPMatrices[] = {
kRGBToRGB8Matrix, kRGBToRGB10Matrix, kRGBToYCoCgMatrix, kRGBToYpUVMatrix};
constexpr const uint32_t kRGBToCCSPShifts[] = {
kRGBToRGB8Shift, kRGBToRGB10Shift, kRGBToYCoCgShift, kRGBToYpUVShift};
class EncodeDecodeCustomCspTest
: public testing::TestWithParam<
std::tuple<std::string, float, Matrix, bool>> {};
//------------------------------------------------------------------------------
TEST_P(EncodeDecodeCustomCspTest, Comparison) {
const std::string& file_name = std::get<0>(GetParam());
const float quality = std::get<1>(GetParam());
const Matrix matrix = std::get<2>(GetParam());
const int16_t* const ccsp_to_rgb_matrix = kCCSPToRGBMatrices[(int)matrix];
const uint32_t ccsp_to_rgb_shift = kCCSPToRGBShifts[(int)matrix];
const int16_t* const rgb_to_ccsp_matrix = kRGBToCCSPMatrices[(int)matrix];
const uint32_t rgb_to_ccsp_shift = kRGBToCCSPShifts[(int)matrix];
const bool encode_alpha = std::get<3>(GetParam());
ArgbBuffer src;
ASSERT_WP2_OK(ReadImage(testutil::GetTestDataPath(file_name).c_str(), &src));
YUVPlane custom_input, custom_output; // Might contain RGB.
CSPTransform csp_transform; // Match Encode() behavior.
constexpr int16_t kRgbAvg[3] = {0, 0, 0};
if (matrix == Matrix::kRGB8 || matrix == Matrix::kRGB10) {
const int16_t v =
1u << (CSPTransform::kMtxShift - ((matrix == Matrix::kRGB8) ? 0 : 2));
const int16_t kRGBToRGBMatrix[9] = {v, 0, 0, 0, v, 0, 0, 0, v}; // Identity
ASSERT_TRUE(csp_transform.Init(kRGBToRGBMatrix, kRgbAvg));
} else if (matrix == Matrix::kYCoCg) {
// 1 1 -1 with 10b fixed-point precision (x 1<<10)
// 1 0 1 so that the inverse will be 14b and thus
// 1 -1 -1 after the shift of 12b, 8+2b remain
constexpr int16_t kYCoCgMatrix[] = {1024, 1024, -1024, 1024, 0,
1024, 1024, -1024, -1024};
ASSERT_TRUE(csp_transform.Init(kYCoCgMatrix, kRgbAvg));
} else {
// 1.0 0.00000 1.13983 with 9b fixed-point precision (x 1<<9)
// 1.0 -0.39465 -0.58060 so that the inverse will be 15b and thus
// 1.0 2.03211 0.00000 after the shift of 12b, 8+3b remain
constexpr int16_t kYpUVMatrix[] = {512, 0, 584, 512, -202,
-297, 512, 1040, 0};
ASSERT_TRUE(csp_transform.Init(kYpUVMatrix, kRgbAvg));
}
ASSERT_WP2_OK(custom_input.Import(src, encode_alpha, csp_transform,
/*resize_if_needed=*/true, /*pad=*/1));
ASSERT_WP2_OK(
custom_output.Resize(src.width(), src.height(), /*pad=*/1, encode_alpha));
MemoryWriter data;
EncoderConfig config = EncoderConfig::kDefault;
config.quality = quality;
ASSERT_WP2_OK(Encode(
src.width(), src.height(), custom_input.Y.Row(0), custom_input.Y.Step(),
custom_input.U.Row(0), custom_input.U.Step(), custom_input.V.Row(0),
custom_input.V.Step(),
custom_input.HasAlpha() ? custom_input.A.Row(0) : nullptr,
custom_input.A.Step(), ccsp_to_rgb_matrix, ccsp_to_rgb_shift, &data,
config));
ASSERT_WP2_OK(Decode(
data.mem_, data.size_, rgb_to_ccsp_matrix, rgb_to_ccsp_shift,
custom_output.Y.Row(0), custom_output.Y.Step(), custom_output.Y.Size(),
custom_output.U.Row(0), custom_output.U.Step(), custom_output.U.Size(),
custom_output.V.Row(0), custom_output.V.Step(), custom_output.V.Size(),
custom_output.HasAlpha() ? custom_output.A.Row(0) : nullptr,
custom_output.A.Step(), custom_output.A.Size()));
// Even if the color space is custom, the actual source is RGB so there is no
// loss due to conversion as there is no real precision beyond 8 bits. However
// there might be some slight rounding differences.
const float expected_distortion =
std::min(testutil::GetExpectedDistortion(quality), 80.f);
ASSERT_TRUE(testutil::Compare(custom_input, custom_output,
csp_transform.GetYuvDepth(),
file_name, expected_distortion));
}
//------------------------------------------------------------------------------
INSTANTIATE_TEST_SUITE_P(
EncodeDecodeCustomCspTestAlpha, EncodeDecodeCustomCspTest,
testing::Combine(testing::Values("source1_1x1.png", "alpha_ramp.png"),
testing::Values(0.f, 100.f) /* quality */,
testing::Values(Matrix::kRGB8, Matrix::kRGB10,
Matrix::kYCoCg, Matrix::kYpUV),
testing::Values(true) /* encode_alpha */));
INSTANTIATE_TEST_SUITE_P(
EncodeDecodeCustomCspTestOpaque, EncodeDecodeCustomCspTest,
testing::Combine(testing::Values("source3_222x167.jpg"),
testing::Values(50.f, 100.f) /* quality */,
testing::Values(Matrix::kRGB8, Matrix::kRGB10,
Matrix::kYCoCg, Matrix::kYpUV),
testing::Values(false) /* encode_alpha */));
//------------------------------------------------------------------------------
} // namespace
} // namespace WP2