|  | /* | 
|  | * Copyright (c) 2024, Alliance for Open Media. All rights reserved. | 
|  | * | 
|  | * This source code is subject to the terms of the BSD 2 Clause License and | 
|  | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License | 
|  | * was not distributed with this source code in the LICENSE file, you can | 
|  | * obtain it at www.aomedia.org/license/software. If the Alliance for Open | 
|  | * Media Patent License 1.0 was not distributed with this source code in the | 
|  | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. | 
|  | */ | 
|  |  | 
|  | #include <cmath> | 
|  |  | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | #include "examples/multilayer_metadata.h" | 
|  | #include "test/video_source.h" | 
|  |  | 
|  | namespace libaom_examples { | 
|  | namespace { | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseAlpha) { | 
|  | const std::string metadata = R"( | 
|  |  | 
|  | use_case: 1 # global alpha | 
|  | layers: | 
|  | - layer_type: 5 # alpha | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 2 # global | 
|  | alpha: | 
|  | alpha_use_idc: 1 # premultiplied | 
|  | alpha_bit_depth: 8 | 
|  | alpha_transparent_value: 0 | 
|  | alpha_opaque_value: 4 | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 2 # global | 
|  | layer_color_description: | 
|  | color_range: 1 | 
|  | color_primaries: 1 | 
|  | transfer_characteristics: 13 | 
|  | matrix_coefficients: 6 | 
|  |  | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | EXPECT_TRUE(parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  |  | 
|  | EXPECT_EQ(multilayer.use_case, 1); | 
|  | ASSERT_EQ(multilayer.layers.size(), 2); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_type, 5); | 
|  | EXPECT_EQ(multilayer.layers[0].luma_plane_only_flag, 1); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_metadata_scope, 2); | 
|  | EXPECT_EQ(multilayer.layers[0].alpha.alpha_use_idc, 1); | 
|  | EXPECT_EQ(multilayer.layers[0].alpha.alpha_bit_depth, 8); | 
|  | EXPECT_EQ(multilayer.layers[0].alpha.alpha_transparent_value, 0); | 
|  | EXPECT_EQ(multilayer.layers[0].alpha.alpha_opaque_value, 4); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_type, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].luma_plane_only_flag, 0); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_metadata_scope, 2); | 
|  | EXPECT_TRUE(multilayer.layers[1].layer_color_description.second); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_range, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_primaries, | 
|  | 1); | 
|  | EXPECT_EQ(multilayer.layers[1] | 
|  | .layer_color_description.first.transfer_characteristics, | 
|  | 13); | 
|  | EXPECT_EQ( | 
|  | multilayer.layers[1].layer_color_description.first.matrix_coefficients, | 
|  | 6); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseDepth) { | 
|  | const std::string metadata = R"( | 
|  | use_case: 2 # global depth | 
|  | layers: | 
|  | - layer_type: 6 # depth | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 2 # global | 
|  | depth: | 
|  | z_near: 1.456 | 
|  | z_far: 9.786 | 
|  | depth_representation_type: 2 | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 2 # global | 
|  | layer_color_description: | 
|  | color_range: 1 | 
|  | color_primaries: 1 | 
|  | transfer_characteristics: 13 | 
|  | matrix_coefficients: 6 | 
|  |  | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | EXPECT_TRUE(parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  | EXPECT_EQ(multilayer.use_case, 2); | 
|  | ASSERT_EQ(multilayer.layers.size(), 2); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_type, 6); | 
|  | EXPECT_EQ(multilayer.layers[0].luma_plane_only_flag, 1); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_metadata_scope, 2); | 
|  | EXPECT_TRUE(multilayer.layers[0].depth.z_near.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].depth.z_near.first), | 
|  | 1.456, 0.00001); | 
|  | EXPECT_TRUE(multilayer.layers[0].depth.z_far.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].depth.z_far.first), | 
|  | 9.786, 0.00001); | 
|  | EXPECT_EQ(multilayer.layers[0].depth.depth_representation_type, 2); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_type, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].luma_plane_only_flag, 0); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_metadata_scope, 2); | 
|  | EXPECT_TRUE(multilayer.layers[1].layer_color_description.second); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_range, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_primaries, | 
|  | 1); | 
|  | EXPECT_EQ(multilayer.layers[1] | 
|  | .layer_color_description.first.transfer_characteristics, | 
|  | 13); | 
|  | EXPECT_EQ( | 
|  | multilayer.layers[1].layer_color_description.first.matrix_coefficients, | 
|  | 6); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseLocalDepth) { | 
|  | const std::string metadata = R"( | 
|  | use_case: 4 # depth | 
|  | layers: | 
|  | - layer_type: 6 # depth | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 3 # mixed | 
|  | depth: | 
|  | z_near: 1.456 | 
|  | z_far: 9.786 | 
|  | depth_representation_type: 2 | 
|  | local_metadata: | 
|  | - frame_idx: 4 | 
|  | depth: | 
|  | z_near: 2.78933 | 
|  | z_far: 20.663 | 
|  | depth_representation_type: 0 | 
|  | - frame_idx: 100 | 
|  | depth: | 
|  | z_near: 0 | 
|  | z_far: 24 | 
|  | depth_representation_type: 0 | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 3 # mixed | 
|  | layer_color_description: | 
|  | color_range: 1 | 
|  | color_primaries: 1 | 
|  | transfer_characteristics: 13 | 
|  | matrix_coefficients: 6 | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | EXPECT_TRUE(parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  | EXPECT_EQ(multilayer.use_case, 4); | 
|  | ASSERT_EQ(multilayer.layers.size(), 2); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_type, 6); | 
|  | EXPECT_EQ(multilayer.layers[0].luma_plane_only_flag, 1); | 
|  | EXPECT_EQ(multilayer.layers[0].layer_metadata_scope, 3); | 
|  | EXPECT_TRUE(multilayer.layers[0].depth.z_near.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].depth.z_near.first), | 
|  | 1.456, 0.00001); | 
|  | EXPECT_TRUE(multilayer.layers[0].depth.z_far.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].depth.z_far.first), | 
|  | 9.786, 0.00001); | 
|  | EXPECT_EQ(multilayer.layers[0].depth.depth_representation_type, 2); | 
|  | ASSERT_EQ(multilayer.layers[0].local_metadata.size(), 2); | 
|  | EXPECT_EQ(multilayer.layers[0].local_metadata[0].frame_idx, 4); | 
|  | EXPECT_TRUE(multilayer.layers[0].local_metadata[0].depth.z_near.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].local_metadata[0].depth.z_near.first), | 
|  | 2.78933, 0.00001); | 
|  | EXPECT_TRUE(multilayer.layers[0].local_metadata[0].depth.z_far.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].local_metadata[0].depth.z_far.first), | 
|  | 20.663, 0.00001); | 
|  | EXPECT_EQ( | 
|  | multilayer.layers[0].local_metadata[0].depth.depth_representation_type, | 
|  | 0); | 
|  | EXPECT_EQ(multilayer.layers[0].local_metadata[1].frame_idx, 100); | 
|  | EXPECT_TRUE(multilayer.layers[0].local_metadata[1].depth.z_near.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].local_metadata[1].depth.z_near.first), | 
|  | 0, 0.00001); | 
|  | EXPECT_TRUE(multilayer.layers[0].local_metadata[1].depth.z_far.second); | 
|  | EXPECT_NEAR(depth_representation_element_to_double( | 
|  | multilayer.layers[0].local_metadata[1].depth.z_far.first), | 
|  | 24, 0.00001); | 
|  | EXPECT_EQ( | 
|  | multilayer.layers[0].local_metadata[1].depth.depth_representation_type, | 
|  | 0); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_type, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].luma_plane_only_flag, 0); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_metadata_scope, 3); | 
|  | EXPECT_TRUE(multilayer.layers[1].layer_color_description.second); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_range, 1); | 
|  | EXPECT_EQ(multilayer.layers[1].layer_color_description.first.color_primaries, | 
|  | 1); | 
|  | EXPECT_EQ(multilayer.layers[1] | 
|  | .layer_color_description.first.transfer_characteristics, | 
|  | 13); | 
|  | EXPECT_EQ( | 
|  | multilayer.layers[1].layer_color_description.first.matrix_coefficients, | 
|  | 6); | 
|  | EXPECT_EQ(multilayer.layers[1].local_metadata.size(), 0); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseInvalid) { | 
|  | const std::string metadata = R"( | 
|  |  | 
|  | use_case: 3 # alpha | 
|  | layers: | 
|  | - layer_type: 5 # alpha | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 3 # mixed | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 3 # mixed | 
|  |  | 
|  | - layer_type: 6 # depth => bad layer type | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 3 # mixed | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | // Invalid: has a depth layer even though use_case is alpha | 
|  | EXPECT_FALSE( | 
|  | parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseBadIndent) { | 
|  | const std::string metadata = R"( | 
|  |  | 
|  | use_case: 1 # global alpha | 
|  | layers: | 
|  | - layer_type: 5 # alpha | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 2 # global | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 2 # global | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | // Invalid indentation. | 
|  | EXPECT_FALSE( | 
|  | parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, ParseUnknownField) { | 
|  | const std::string metadata = R"( | 
|  |  | 
|  | use_case: 1 # global alpha | 
|  | layers: | 
|  | - layer_type: 5 # alpha | 
|  | luma_plane_only_flag: 1 | 
|  | layer_metadata_scope: 2 # global | 
|  | foobar: 42 | 
|  |  | 
|  | - layer_type: 1 # texture | 
|  | luma_plane_only_flag: 0 | 
|  | layer_metadata_scope: 2 # global | 
|  | )"; | 
|  | libaom_test::TempOutFile tmp_file(/*text_mode=*/true); | 
|  | fprintf(tmp_file.file(), "%s", metadata.c_str()); | 
|  | fflush(tmp_file.file()); | 
|  |  | 
|  | MultilayerMetadata multilayer; | 
|  | // Unkonwn field 'foobar'. | 
|  | EXPECT_FALSE( | 
|  | parse_multilayer_file(tmp_file.file_name().c_str(), &multilayer)); | 
|  | } | 
|  |  | 
|  | void TestConversion(double v) { | 
|  | DepthRepresentationElement e; | 
|  | ASSERT_TRUE(double_to_depth_representation_element(v, &e)) << v; | 
|  | EXPECT_NEAR(depth_representation_element_to_double(e), v, 0.000000001); | 
|  | } | 
|  |  | 
|  | TEST(MultilayerMetadataTest, DoubleConversion) { | 
|  | TestConversion(0.0); | 
|  | TestConversion(1.789456e-5); | 
|  | TestConversion(-1.789456e-5); | 
|  | TestConversion(42); | 
|  | TestConversion(6.7894564456); | 
|  | TestConversion(6.7894564456e10); | 
|  | TestConversion(-6.7894564456e10); | 
|  |  | 
|  | DepthRepresentationElement e; | 
|  | // Too small. | 
|  | ASSERT_FALSE(double_to_depth_representation_element(1e-10, &e)); | 
|  | // Too big. | 
|  | ASSERT_FALSE(double_to_depth_representation_element(1e+30, &e)); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace libaom_examples |