| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/base/video_codec_string_parsers.h" |
| |
| #include "base/containers/flat_set.h" |
| #include "base/strings/stringprintf.h" |
| #include "media/base/video_color_space.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media { |
| |
| TEST(ParseVP9CodecId, NewStyleVP9CodecIDs) { |
| // Old style is not subset of new style. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp8")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp9")); |
| |
| // Parsing should fail when first 4 required fields are not provided. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.00")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.00.10")); |
| |
| // Expect success when all required fields supplied (and valid). |
| // TransferID not specified by string, should default to 709. |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.00.10.08"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoCodec::kVP9, result->codec); |
| EXPECT_EQ(VP9PROFILE_PROFILE0, result->profile); |
| EXPECT_EQ(10u, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, result->color_space.transfer); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| EXPECT_EQ(8u, result->bit_depth); |
| } |
| |
| // Verify profile's 1, 2, and 3 parse correctly. |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.01.10.08"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VP9PROFILE_PROFILE1, result->profile); |
| EXPECT_EQ(8u, result->bit_depth); |
| } |
| |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VP9PROFILE_PROFILE2, result->profile); |
| EXPECT_EQ(10u, result->bit_depth); |
| } |
| |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.03.10.12"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VP9PROFILE_PROFILE3, result->profile); |
| EXPECT_EQ(12u, result->bit_depth); |
| } |
| |
| // Profile 4 is not a thing. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.04.10.08")); |
| |
| // Verify valid levels parse correctly. |
| const base::flat_set<uint32_t> kValidVp9Levels = {10, 11, 20, 21, 30, 31, 40, |
| 41, 50, 51, 52, 60, 61, 62}; |
| size_t num_valid_levels = 0; |
| for (uint32_t i = 0; i < 99; ++i) { |
| // Write "i" as the level. |
| auto codec_string = base::StringPrintf("vp09.00.%02d.08", i); |
| if (kValidVp9Levels.find(i) != kValidVp9Levels.end()) { |
| auto result = ParseNewStyleVp9CodecID(codec_string); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VP9PROFILE_PROFILE0, result->profile); |
| EXPECT_EQ(i, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, |
| result->color_space.transfer); |
| num_valid_levels++; |
| } else { |
| EXPECT_FALSE(ParseNewStyleVp9CodecID(codec_string)); |
| } |
| } |
| EXPECT_EQ(kValidVp9Levels.size(), num_valid_levels); |
| |
| // Verify bitdepths. Only 8, 10, 12 are valid. |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.8")); |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10")); |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.12")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.13")); |
| |
| // Verify chroma subsampling values. |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.00"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.01"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.01.10.10"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.03.10.10"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.01.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.03.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.01.10.10.03"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.03.10.10.03"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling); |
| } |
| |
| // Values 4 - 7 are reserved. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.04")); |
| |
| // Test invalid profile + sampling combinations. These are invalid but due to |
| // in the wild usage will just return the default subsampling value. |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.00.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.00.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.02"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.03"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| { |
| auto result = ParseNewStyleVp9CodecID("vp09.02.10.10.03"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| } |
| |
| // Verify a few color profiles. |
| // BT709 |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01")); |
| // BT2020 |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.09")); |
| // 0 is invalid. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.00")); |
| // 23 - 255 are reserved. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.23")); |
| |
| // Verify a few common EOTFs parse correctly. |
| for (int eotf : {1, 4, 6, 14, 15, 13, 16}) { |
| auto codec_string = base::StringPrintf("vp09.02.10.10.00.01.%02d", eotf); |
| auto result = ParseNewStyleVp9CodecID(codec_string); |
| ASSERT_TRUE(result) << "eotf=" << eotf; |
| EXPECT_EQ(static_cast<VideoColorSpace::TransferID>(eotf), |
| result->color_space.transfer); |
| } |
| |
| // Verify 0 and 3 are reserved EOTF values. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.08.00.01.00")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.08.00.01.03")); |
| |
| // Verify a few matrix coefficients. |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.00")); |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.01")); |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.10")); |
| // Values 12 - 255 reserved. |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.12")); |
| |
| // Verify full range flag (boolean 0 or 1). |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.01.00")); |
| EXPECT_TRUE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.01.01")); |
| EXPECT_FALSE(ParseNewStyleVp9CodecID("vp09.02.10.10.00.01.01.01.02")); |
| } |
| |
| TEST(ParseAv1CodecId, VerifyRequiredValues) { |
| // Old style is not subset of new style. |
| EXPECT_FALSE(ParseAv1CodecId("av1")); |
| |
| // Parsing should fail when first 4 required fields are not provided. |
| EXPECT_FALSE(ParseAv1CodecId("av01")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.04M")); |
| |
| // Expect success when all required fields supplied (and valid). |
| // TransferID not specified by string, should default to 709. |
| { |
| auto result = ParseAv1CodecId("av01.0.04M.08"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoCodec::kAV1, result->codec); |
| EXPECT_EQ(AV1PROFILE_PROFILE_MAIN, result->profile); |
| EXPECT_EQ(4u, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, result->color_space.transfer); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling); |
| EXPECT_EQ(8u, result->bit_depth); |
| } |
| |
| // Verify high and pro profiles parse correctly. |
| { |
| auto result = ParseAv1CodecId("av01.1.04M.10"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(AV1PROFILE_PROFILE_HIGH, result->profile); |
| EXPECT_EQ(10u, result->bit_depth); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling); |
| } |
| |
| { |
| auto result = ParseAv1CodecId("av01.2.04M.12"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(AV1PROFILE_PROFILE_PRO, result->profile); |
| EXPECT_EQ(12u, result->bit_depth); |
| } |
| // Leading zeros or negative values are forbidden. |
| EXPECT_FALSE(ParseAv1CodecId("av01.00.04M.08")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.-0.04M.08")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.-1.04M.08")); |
| |
| // There are no profile values > 2 |
| for (int i = 3; i <= 9; ++i) { |
| const std::string codec_string = base::StringPrintf("av01.%d.00M.08", i); |
| SCOPED_TRACE(codec_string); |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| |
| // Leading zeros are required for the level. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.4M.08")); |
| |
| // Negative values are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.-4M.08")); |
| |
| // Verify valid levels parse correctly. Valid profiles are 00 -> 31. |
| for (uint32_t i = 0; i < 99; ++i) { |
| const std::string codec_string = base::StringPrintf("av01.0.%02dM.08", i); |
| SCOPED_TRACE(codec_string); |
| |
| if (i < 32) { |
| auto result = ParseAv1CodecId(codec_string); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(AV1PROFILE_PROFILE_MAIN, result->profile); |
| EXPECT_EQ(i, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, |
| result->color_space.transfer); |
| } else { |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| } |
| |
| // Verify tier parses correctly. |
| for (char c = '\0'; c <= '\255'; ++c) { |
| const std::string codec_string = base::StringPrintf("av01.1.00%c.08", c); |
| SCOPED_TRACE(codec_string); |
| |
| if (c == 'M' || c == 'H') { |
| auto result = ParseAv1CodecId(codec_string); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(AV1PROFILE_PROFILE_HIGH, result->profile); |
| EXPECT_EQ(0u, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, |
| result->color_space.transfer); |
| } else { |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| } |
| |
| // Leading zeros are required for the bit depth. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.04M.8")); |
| |
| // Verify bitdepths. Only 8, 10, 12 are valid. |
| for (int i = 0; i < 99; ++i) { |
| const std::string codec_string = base::StringPrintf("av01.0.00M.%02d", i); |
| SCOPED_TRACE(codec_string); |
| |
| if (i == 8 || i == 10 || i == 12) { |
| auto result = ParseAv1CodecId(codec_string); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(AV1PROFILE_PROFILE_MAIN, result->profile); |
| EXPECT_EQ(0u, result->level); |
| EXPECT_EQ(VideoColorSpace::TransferID::BT709, |
| result->color_space.transfer); |
| } else { |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| } |
| } |
| |
| TEST(ParseAv1CodecId, VerifyOptionalMonochrome) { |
| // monochrome is either 0, 1 and leading zeros are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.04M.08.00")); |
| |
| // monochrome is not allowed with high profile. |
| EXPECT_FALSE(ParseAv1CodecId("av01.1.04M.08.1")); |
| |
| for (int i = 0; i <= 9; ++i) { |
| const std::string codec_string = base::StringPrintf("av01.0.00M.08.%d", i); |
| SCOPED_TRACE(codec_string); |
| if (i < 2) { |
| auto result = ParseAv1CodecId(codec_string); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, |
| i == 0 ? VideoChromaSampling::k420 : VideoChromaSampling::k400); |
| } else { |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| } |
| } |
| |
| TEST(ParseAv1CodecId, VerifyOptionalSubsampling) { |
| // chroma subsampling values are {0,1}{0,1}{0,3} with the last value always |
| // zero if either of the first two values are zero. |
| { |
| auto result = ParseAv1CodecId("av01.1.00M.10.0.000"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k444); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.2.00M.10.0.000"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k444); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.2.00M.10.0.100"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k422); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.010"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.111"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.112"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.113"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| |
| // Invalid cases. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.101")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.102")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.103")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.011")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.012")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.013")); |
| |
| // These are invalid but due to in the wild usage will just return the |
| // default subsampling value. |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.100"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.1.00M.10.0.100"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k444); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.000"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| |
| // The last-value may be non-zero if the first two values are non-zero. |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.2.00M.10.0.100"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k422); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.010"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(result->subsampling, VideoChromaSampling::k420); |
| } |
| |
| for (int i = 2; i <= 9; ++i) { |
| for (int j = 2; j <= 9; ++j) { |
| for (int k = 4; k <= 9; ++k) { |
| const std::string codec_string = |
| base::StringPrintf("av01.0.00M.08.0.%d%d%d", i, j, k); |
| SCOPED_TRACE(codec_string); |
| EXPECT_FALSE(ParseAv1CodecId(codec_string)); |
| } |
| } |
| } |
| } |
| |
| TEST(ParseAv1CodecId, VerifyOptionalColorProperties) { |
| // Verify a few color properties. This is non-exhaustive since validation is |
| // handled by common color space function. Below we validate only portions |
| // specific to the AV1 codec string. |
| |
| // Leading zeros must be provided. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.1")); |
| // Negative values are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.000.-1")); |
| |
| // BT709 |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoColorSpace::PrimaryID::BT709, result->color_space.primaries); |
| } |
| // BT2020 |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.09"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoColorSpace::PrimaryID::BT2020, |
| result->color_space.primaries); |
| } |
| // 0 is invalid. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.00")); |
| // 23 - 255 are reserved. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.23")); |
| |
| // Leading zeros must be provided. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.1")); |
| // Negative values are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.-1")); |
| |
| // Verify a few common EOTFs parse correctly. |
| for (int eotf : {1, 4, 6, 14, 15, 13, 16}) { |
| auto codec_string = base::StringPrintf("av01.0.00M.10.0.110.01.%02d", eotf); |
| auto result = ParseAv1CodecId(codec_string); |
| ASSERT_TRUE(result) << "eotf=" << eotf; |
| EXPECT_EQ(static_cast<VideoColorSpace::TransferID>(eotf), |
| result->color_space.transfer); |
| } |
| |
| // Verify 0 and 3 are reserved EOTF values. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.00")); |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.03")); |
| |
| // Leading zeros must be provided. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.1")); |
| // Negative values are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.-1")); |
| |
| // Verify a few matrix coefficients. |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoColorSpace::MatrixID::RGB, result->color_space.matrix); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.01"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoColorSpace::MatrixID::BT709, result->color_space.matrix); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.10"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoColorSpace::MatrixID::BT2020_CL, result->color_space.matrix); |
| } |
| |
| // Values 12 - 255 reserved. Though 12 at least is a valid value we should |
| // support in the future. https://crbug.com/854290 |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.12")); |
| |
| // Leading zeros are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.00")); |
| // Negative values are not allowed. |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.-1")); |
| |
| // Verify full range flag (boolean 0 or 1). |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(gfx::ColorSpace::RangeID::LIMITED, result->color_space.range); |
| } |
| { |
| auto result = ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.1"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(gfx::ColorSpace::RangeID::FULL, result->color_space.range); |
| } |
| EXPECT_FALSE(ParseAv1CodecId("av01.0.00M.10.0.110.01.01.00.2")); |
| } |
| |
| TEST(ParseHEVCCodecIdTest, InvalidHEVCCodecIds) { |
| // Both hev1 and hvc1 should be supported |
| { |
| auto result = ParseHEVCCodecId("hev1.1.6.L93.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoCodec::kHEVC, result->codec); |
| EXPECT_EQ(HEVCPROFILE_MAIN, result->profile); |
| EXPECT_EQ(93u, result->level); |
| } |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L93.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MAIN, result->profile); |
| EXPECT_EQ(93u, result->level); |
| } |
| |
| // Check that codec id string with insufficient number of dot-separated |
| // elements are rejected. There must be at least 4 elements: hev1/hvc1 prefix, |
| // profile, profile_compatibility, tier+level. |
| { |
| auto result = ParseHEVCCodecId("hev1.1.6.L93"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MAIN, result->profile); |
| EXPECT_EQ(93u, result->level); |
| } |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1")); |
| EXPECT_FALSE(ParseHEVCCodecId("hev1")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1...")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1....")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1...")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6...")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1..L93")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1..L93.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1..L93..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6...")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6.L93")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6.L93.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1..6.L93..")); |
| |
| // Check that codec ids with empty constraint bytes are rejected. |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93...")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93....")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.....")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93......")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.......")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.......0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.0.")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.0..")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.0..0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.0..0.0.0.0.0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L93.0.0.0.0.0.0.")); |
| |
| // Different variations of general_profile_space (empty, 'A', 'B', 'C') |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.A1.6.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.B1.6.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.C1.6.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.D1.6.L93.B0")); |
| |
| // general_profile_idc (the number after the first dot) must be a 5-bit |
| // decimal-encoded number (between 0 and 31) |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.0.6.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.31.6.L93.B0")); |
| |
| // Spec A.3.2 |
| // When general_profile_compatibility_flag[1] is equal to 1, |
| // general_profile_compatibility_flag[2] should be equal to 1 as well. |
| for (const auto* codec_id : |
| {"hvc1.1.6.L93.B0", "hvc1.1.0.L93.B0", "hvc1.0.6.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MAIN, result->profile); |
| } |
| |
| // Spec A.3.3 |
| for (const auto* codec_id : |
| {"hvc1.2.4.L93.B0", "hvc1.2.0.L93.B0", "hvc1.0.4.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MAIN10, result->profile); |
| } |
| |
| // Spec A.3.4 |
| // When general_profile_compatibility_flag[3] is equal to 1, |
| // general_profile_compatibility_flag[1] and |
| // general_profile_compatibility_flag[2] should be equal to 1 as well. |
| for (const auto* codec_id : |
| {"hvc1.3.E.L93.B0", "hvc1.0.E.L93.B0", "hvc1.3.0.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MAIN_STILL_PICTURE, result->profile); |
| } |
| |
| // Spec A.3.5 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.B0", "hvc1.4.0.L93.B0", "hvc1.0.10.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| } |
| |
| if (base::FeatureList::IsEnabled(kHEVCRextCodecStringParsing)) { |
| // HEVC range extension 8b444 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.9E.28", "hvc1.4.10.L93.9E.20", "hvc1.4.10.L93.9E.8"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(8u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling.value()); |
| } |
| // HEVC range extension 10b422. For 8-bit 422, the constraint flag is the |
| // same as 10-bit 422, so the bit depth will be 10 here to indicate the |
| // maximum supported value. |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.9D.28", "hvc1.4.10.L93.9D.20", "hvc1.4.10.L93.9D.8"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(10u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling.value()); |
| } |
| // HEVC range extension 10b444 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.9C.28", "hvc1.4.10.L93.9C.20", "hvc1.4.10.L93.9C.8"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(10u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling.value()); |
| } |
| // HEVC range extension 12b420 |
| for (const auto* codec_id : {"hvc1.4.10.L93.99.A0", "hvc1.4.10.L93.99.A8", |
| "hvc1.4.10.L93.99.88"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(12u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k420, result->subsampling.value()); |
| } |
| // HEVC range extension 12b422 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.99.20", "hvc1.4.10.L93.99.28", "hvc1.4.0.L93.99.8"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(12u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k422, result->subsampling.value()); |
| } |
| // HEVC range extension 12b444 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.98.20", "hvc1.4.10.L93.98.28", "hvc1.4.0.L93.98.8"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(12u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling.value()); |
| } |
| // HEVC range extension 16b monochrome |
| { |
| auto result = ParseHEVCCodecId("hvc1.4.10.L93.91.C8"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(16u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k400, result->subsampling.value()); |
| } |
| |
| // HEVC range extension 16b444 |
| for (const auto* codec_id : |
| {"hvc1.4.10.L93.90.20", "hvc1.4.10.L93.90.28"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_REXT, result->profile); |
| EXPECT_TRUE(result->bit_depth.has_value()); |
| EXPECT_EQ(16u, result->bit_depth.value()); |
| EXPECT_TRUE(result->subsampling.has_value()); |
| EXPECT_EQ(VideoChromaSampling::k444, result->subsampling.value()); |
| } |
| |
| // max_bits_flag must be valid for range extension. |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.4.10.L93.90.C8")); |
| |
| // max_422_flag/max_444_flag/max_monochrome_flag combination must be valid. |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.4.10.L93.99.48")); |
| } |
| |
| // Spec A.3.6 |
| for (const auto* codec_id : |
| {"hvc1.5.20.L93.B0", "hvc1.5.0.L93.B0", "hvc1.0.20.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_HIGH_THROUGHPUT, result->profile); |
| } |
| |
| // Spec G.11.1.1 |
| for (const auto* codec_id : |
| {"hvc1.6.40.L93.B0", "hvc1.6.0.L93.B0", "hvc1.0.40.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_MULTIVIEW_MAIN, result->profile); |
| } |
| |
| // Spec H.11.1.1 |
| for (const auto* codec_id : |
| {"hvc1.7.80.L93.B0", "hvc1.7.0.L93.B0", "hvc1.0.80.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_SCALABLE_MAIN, result->profile); |
| } |
| |
| // Spec I.11.1.1 |
| for (const auto* codec_id : |
| {"hvc1.8.100.L93.B0", "hvc1.8.0.L93.B0", "hvc1.0.100.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_3D_MAIN, result->profile); |
| } |
| |
| // Spec A.3.7 |
| for (const auto* codec_id : |
| {"hvc1.9.200.L93.B0", "hvc1.9.0.L93.B0", "hvc1.0.200.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_SCREEN_EXTENDED, result->profile); |
| } |
| |
| // Spec H.11.1.2 |
| for (const auto* codec_id : |
| {"hvc1.10.400.L93.B0", "hvc1.10.0.L93.B0", "hvc1.0.400.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_SCALABLE_REXT, result->profile); |
| } |
| |
| // Spec A.3.8 |
| for (const auto* codec_id : |
| {"hvc1.11.800.L93.B0", "hvc1.11.0.L93.B0", "hvc1.0.800.L93.B0"}) { |
| auto result = ParseHEVCCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED, result->profile); |
| } |
| |
| // Unmatched general_profile_idc and general_profile_compatibility_flags |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.12.1000.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.12.0.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.0.1000.L93.B0")); |
| |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.-1.6.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.32.6.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.999.6.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.A.6.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1F.6.L93.B0")); |
| |
| // general_profile_compatibility_flags is a 32-bit hex number |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.0.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.FF.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.FFFF.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.FFFFFFFF.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.100000000.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.FFFFFFFFF.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.-1.L93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.0G.L93.B0")); |
| |
| // general_tier_flag is encoded as either character 'L' (general_tier_flag==0) |
| // or character 'H' (general_tier_flag==1) in the fourth element of the string |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L93.B0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.0.H93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.0.93.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.0.A93.B0")); |
| |
| // general_level_idc is 8-bit decimal-encoded number after general_tier_flag. |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L0.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(0u, result->level); |
| } |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L1.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(1u, result->level); |
| } |
| // Level 3.1 (93 == 3.1 * 30) |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L93.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(93u, result->level); |
| } |
| // Level 5 (150 == 5 * 30) |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L150.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(150u, result->level); |
| } |
| { |
| auto result = ParseHEVCCodecId("hvc1.1.6.L255.B0"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(255u, result->level); |
| } |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L256.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L999.B0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L-1.B0")); |
| |
| // The elements after the fourth dot are hex-encoded bytes containing |
| // constraint flags (up to 6 bytes), trailing zero bytes may be omitted |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.0.0.0.0.0.0")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.00.00.00.00.00.00")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.12")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.12.34.56")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.12.34.56.78.9A.BC")); |
| EXPECT_TRUE(ParseHEVCCodecId("hvc1.1.6.L0.FF.FF.FF.FF.FF.FF")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L0.FF.FF.FF.FF.FF.FF.0")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L0.100")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L0.1FF")); |
| EXPECT_FALSE(ParseHEVCCodecId("hvc1.1.6.L0.-1")); |
| } |
| |
| TEST(ParseVVCCodecIdTest, InvalidVVCCodecIds) { |
| // Both vvc1 and vvi1 should be supported |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L51.CQA.O1+3"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VVCPROFILE_MAIN10, result->profile); |
| EXPECT_EQ(51u, result->level); |
| } |
| { |
| auto result = ParseVVCCodecId("vvi1.2.L83.CQA.S25+YA.O2+3"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VVCPROFILE_MAIN12, result->profile); |
| EXPECT_EQ(83u, result->level); |
| } |
| |
| // Check that codec id string with insufficient number of dot-separated |
| // elements are rejected. There must be at least 4 elements: vvc1/vvi1 prefix, |
| // profile, level, constraints. |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L51.CQA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VVCPROFILE_MAIN10, result->profile); |
| EXPECT_EQ(51u, result->level); |
| } |
| EXPECT_FALSE(ParseVVCCodecId("vvc1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvi1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1..")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1...")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1....")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1..")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1...")); |
| |
| // Check that codec ids with invalid trailing bytes are rejected. |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83..")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83...")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83....")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.....")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83......")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.......")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.......0")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.0.")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.0..")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.0..0")); |
| |
| // general_profile_idc (the number after the first dot) must be a 5-bit |
| // decimal-encoded number (between 1 and 99) |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L83.CQA")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.99.L83.CQA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.100.L83.CQA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.0.L83.CQA")); |
| |
| // general_tier_flag is encoded as either character 'L' (general_tier_flag==0) |
| // or character 'H' (general_tier_flag==1) in the 3rd element of the string |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L83.CQA")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.H83.CQA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.83.CQA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.A83.CQA")); |
| |
| // general_level_idc is 8-bit decimal-encoded number after general_tier_flag. |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L0.CQA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(0u, result->level); |
| } |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L1.CQA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(1u, result->level); |
| } |
| // Level 3.1 (51 == 3 * 16 + 1 * 3) |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L51.CQA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(51u, result->level); |
| } |
| // Level 6.2 (102 == 6 * 16 + 2 * 3) |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L102.CYA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(102u, result->level); |
| } |
| { |
| auto result = ParseVVCCodecId("vvc1.1.L255.CYA"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(255u, result->level); |
| } |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L256.CYA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L999.CQA")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L-1.CQA")); |
| |
| // constraints string |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.100.L83.C.")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.100.L83.2C")); |
| |
| // general_sub_profile_idc placement. |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1.O0+3")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.SF1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1.")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1+AB.O0+3")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1+AB+2B.O0+3")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.SF1.CQA.O0+3")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.O0+3.SF1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.O0+3.S")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.O0+3.S.")); |
| |
| // OlsIdx & MaxTid |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.O0+3")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.O1")); |
| // When MaxTid does not exist, "+" should not be present. |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.O1+")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.O")); |
| EXPECT_TRUE(ParseVVCCodecId("vvc1.1.L0.CQA.O+3")); |
| |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.100")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.1FF")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L83.-1")); |
| EXPECT_FALSE(ParseVVCCodecId("vvc1.1.L0.CQA.SF1.O0+3.100")); |
| } |
| |
| TEST(ParseDolbyVisionCodecIdTest, InvalidDolbyVisionCodecIds) { |
| // Codec dvav/dva1 should only contain profile 0. |
| { |
| auto result = ParseDolbyVisionCodecId("dvav.00.07"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(VideoCodec::kDolbyVision, result->codec); |
| EXPECT_EQ(DOLBYVISION_PROFILE0, result->profile); |
| EXPECT_EQ(7u, result->level); |
| } |
| { |
| auto result = ParseDolbyVisionCodecId("dva1.00.07"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(DOLBYVISION_PROFILE0, result->profile); |
| EXPECT_EQ(7u, result->level); |
| } |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvav.04.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dva1.04.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvav.05.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dva1.05.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvav.07.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dva1.07.07")); |
| |
| // Codec dvhe/dvh1 should only contain profile 5, and 7. |
| { |
| auto result = ParseDolbyVisionCodecId("dvhe.05.07"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(DOLBYVISION_PROFILE5, result->profile); |
| EXPECT_EQ(7u, result->level); |
| } |
| { |
| auto result = ParseDolbyVisionCodecId("dvh1.05.07"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(DOLBYVISION_PROFILE5, result->profile); |
| EXPECT_EQ(7u, result->level); |
| } |
| { |
| auto result = ParseDolbyVisionCodecId("dvhe.07.07"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(DOLBYVISION_PROFILE7, result->profile); |
| EXPECT_EQ(7u, result->level); |
| } |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.00.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvh1.00.07")); |
| |
| // Profiles 1, 2, 3, 4 and 6 are deprecated. |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvav.01.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.02.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.03.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.04.07")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.06.07")); |
| |
| // Level should be two digit number and in the range [01, 13]. |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.00")); |
| |
| for (uint32_t level : {1, 9, 10, 13}) { |
| auto codec_id = base::StringPrintf("dvhe.05.%02d", level); |
| auto result = ParseDolbyVisionCodecId(codec_id); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(DOLBYVISION_PROFILE5, result->profile); |
| EXPECT_EQ(level, result->level); |
| } |
| |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.14")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.20")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.99")); |
| |
| // Valid codec string is <FourCC>.<two digits profile>.<two digits level>. |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe..")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe...")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe....")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5.")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5..")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5...")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5.7")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5.7.")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5.7..")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.5.7...")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.7")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe.05.007")); |
| EXPECT_FALSE(ParseDolbyVisionCodecId("dvhe..5")); |
| } |
| |
| } // namespace media |