| // Copyright 2019 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/formats/mp4/hevc.h" |
| |
| #include "media/formats/mp4/nalu_test_helper.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media { |
| namespace mp4 { |
| |
| TEST(HEVCAnalyzeAnnexBTest, ValidAnnexBConstructs) { |
| struct { |
| const char* case_string; |
| const bool is_keyframe; |
| } test_cases[] = { |
| {"I", true}, {"I I I I", true}, {"AUD I", true}, |
| {"AUD SPS I", true}, {"I EOS", true}, {"I EOS EOB", true}, |
| {"I EOB", true}, {"P", false}, {"P P P P", false}, |
| {"AUD SPS P", false}, {"AUD,I", true}, {"AUD,SPS,I", true}, |
| }; |
| |
| for (size_t i = 0; i < std::size(test_cases); ++i) { |
| std::vector<uint8_t> buf; |
| std::vector<SubsampleEntry> subsamples; |
| HevcStringToAnnexB(test_cases[i].case_string, &buf, nullptr); |
| |
| BitstreamConverter::AnalysisResult expected; |
| expected.is_conformant = true; |
| expected.is_keyframe = test_cases[i].is_keyframe; |
| EXPECT_PRED2(AnalysesMatch, |
| HEVC::AnalyzeAnnexB(buf.data(), buf.size(), subsamples), |
| expected) |
| << "'" << test_cases[i].case_string << "' failed"; |
| } |
| } |
| |
| TEST(HEVCAnalyzeAnnexBTest, InvalidAnnexBConstructs) { |
| struct { |
| const char* case_string; |
| const absl::optional<bool> is_keyframe; |
| } test_cases[] = { |
| // For these cases, lack of conformance is determined before detecting any |
| // IDR or non-IDR slices, so the non-conformant frames' keyframe analysis |
| // reports absl::nullopt (which means undetermined analysis result). |
| {"AUD", absl::nullopt}, // No VCL present. |
| {"AUD,SPS", absl::nullopt}, // No VCL present. |
| {"SPS AUD I", absl::nullopt}, // Parameter sets must come after AUD. |
| {"EOS", absl::nullopt}, // EOS must come after a VCL. |
| {"EOB", absl::nullopt}, // EOB must come after a VCL. |
| |
| // For these cases, IDR slice is first VCL and is detected before |
| // conformance failure, so the non-conformant frame is reported as a |
| // keyframe. |
| {"I EOB EOS", true}, // EOS must come before EOB. |
| {"I SPS", true}, // SPS must come before first VCL. |
| |
| // For this case, P slice is first VCL and is detected before conformance |
| // failure, so the non-conformant frame is reported as a non-keyframe. |
| {"P SPS P", |
| false}, // SPS after first VCL would indicate a new access unit. |
| }; |
| |
| BitstreamConverter::AnalysisResult expected; |
| expected.is_conformant = false; |
| |
| for (size_t i = 0; i < std::size(test_cases); ++i) { |
| std::vector<uint8_t> buf; |
| std::vector<SubsampleEntry> subsamples; |
| HevcStringToAnnexB(test_cases[i].case_string, &buf, nullptr); |
| expected.is_keyframe = test_cases[i].is_keyframe; |
| EXPECT_PRED2(AnalysesMatch, |
| HEVC::AnalyzeAnnexB(buf.data(), buf.size(), subsamples), |
| expected) |
| << "'" << test_cases[i].case_string << "' failed"; |
| } |
| } |
| |
| TEST(HEVCAnalyzeAnnexBTest, HEVCDecoderConfigurationRecordTakenFromStream) { |
| std::vector<uint8_t> test_data{ |
| 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x3c, 0xf0, 0x00, 0xfc, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x03, 0x20, |
| 0x00, 0x01, 0x00, 0x18, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, |
| 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, |
| 0x3c, 0x95, 0xc0, 0x90, 0x21, 0x00, 0x01, 0x00, 0x27, 0x42, 0x01, 0x01, |
| 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, |
| 0x03, 0x00, 0x3c, 0xa0, 0x0a, 0x08, 0x0b, 0x9f, 0x79, 0x65, 0x79, 0x24, |
| 0xca, 0xe0, 0x10, 0x00, 0x00, 0x06, 0x40, 0x00, 0x00, 0xbb, 0x50, 0x80, |
| 0x22, 0x00, 0x01, 0x00, 0x06, 0x44, 0x01, 0xc1, 0x73, 0xd1, 0x89}; |
| HEVCDecoderConfigurationRecord record; |
| EXPECT_TRUE(record.Parse(test_data.data(), test_data.size())); |
| std::vector<uint8_t> output; |
| EXPECT_TRUE(record.Serialize(output)); |
| EXPECT_TRUE(test_data == output); |
| } |
| |
| } // namespace mp4 |
| } // namespace media |