| /* | |
| * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "modules/video_coding/svc/scalability_structure_l2t2_key_shift.h" | |
| #include <span> | |
| #include <vector> | |
| #include "common_video/generic_frame_descriptor/generic_frame_info.h" | |
| #include "modules/video_coding/svc/scalability_structure_test_helpers.h" | |
| #include "test/gmock.h" | |
| #include "test/gtest.h" | |
| namespace webrtc { | |
| namespace { | |
| using ::testing::ElementsAre; | |
| using ::testing::IsEmpty; | |
| using ::testing::SizeIs; | |
| // S1T1 3 7 | |
| // / / | |
| // S1T0 1---5---9 | |
| // | | |
| // S0T1 | 4 8 | |
| // | / / | |
| // S0T0 0-2---6 | |
| // Time-> 0 1 2 3 4 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, DecodeTargetsAreEnabledByDefault) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/5, frames); | |
| ASSERT_THAT(frames, SizeIs(10)); | |
| EXPECT_EQ(frames[0].spatial_id, 0); | |
| EXPECT_EQ(frames[1].spatial_id, 1); | |
| EXPECT_EQ(frames[2].spatial_id, 0); | |
| EXPECT_EQ(frames[3].spatial_id, 1); | |
| EXPECT_EQ(frames[4].spatial_id, 0); | |
| EXPECT_EQ(frames[5].spatial_id, 1); | |
| EXPECT_EQ(frames[6].spatial_id, 0); | |
| EXPECT_EQ(frames[7].spatial_id, 1); | |
| EXPECT_EQ(frames[8].spatial_id, 0); | |
| EXPECT_EQ(frames[9].spatial_id, 1); | |
| // spatial_id = 0 has the temporal shift. | |
| EXPECT_EQ(frames[0].temporal_id, 0); | |
| EXPECT_EQ(frames[2].temporal_id, 0); | |
| EXPECT_EQ(frames[4].temporal_id, 1); | |
| EXPECT_EQ(frames[6].temporal_id, 0); | |
| EXPECT_EQ(frames[8].temporal_id, 1); | |
| // spatial_id = 1 hasn't temporal shift. | |
| EXPECT_EQ(frames[1].temporal_id, 0); | |
| EXPECT_EQ(frames[3].temporal_id, 1); | |
| EXPECT_EQ(frames[5].temporal_id, 0); | |
| EXPECT_EQ(frames[7].temporal_id, 1); | |
| EXPECT_EQ(frames[9].temporal_id, 0); | |
| // Key frame diff. | |
| EXPECT_THAT(frames[0].frame_diffs, IsEmpty()); | |
| EXPECT_THAT(frames[1].frame_diffs, ElementsAre(1)); | |
| // S0T0 frame diffs | |
| EXPECT_THAT(frames[2].frame_diffs, ElementsAre(2)); | |
| EXPECT_THAT(frames[6].frame_diffs, ElementsAre(4)); | |
| // S1T0 frame diffs | |
| EXPECT_THAT(frames[5].frame_diffs, ElementsAre(4)); | |
| EXPECT_THAT(frames[9].frame_diffs, ElementsAre(4)); | |
| // T1 frames refer T0 frame of same spatial layer which is 2 frame ids away. | |
| EXPECT_THAT(frames[3].frame_diffs, ElementsAre(2)); | |
| EXPECT_THAT(frames[4].frame_diffs, ElementsAre(2)); | |
| EXPECT_THAT(frames[7].frame_diffs, ElementsAre(2)); | |
| EXPECT_THAT(frames[8].frame_diffs, ElementsAre(2)); | |
| } | |
| // S1T0 1---4---7 | |
| // | | |
| // S0T1 | 3 6 | |
| // | / / | |
| // S0T0 0-2---5-- | |
| // Time-> 0 1 2 3 4 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, DisableS1T1Layer) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/1)); | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/5, frames); | |
| ASSERT_THAT(frames, SizeIs(8)); | |
| EXPECT_EQ(frames[0].spatial_id, 0); | |
| EXPECT_EQ(frames[1].spatial_id, 1); | |
| EXPECT_EQ(frames[2].spatial_id, 0); | |
| EXPECT_EQ(frames[3].spatial_id, 0); | |
| EXPECT_EQ(frames[4].spatial_id, 1); | |
| EXPECT_EQ(frames[5].spatial_id, 0); | |
| EXPECT_EQ(frames[6].spatial_id, 0); | |
| EXPECT_EQ(frames[7].spatial_id, 1); | |
| // spatial_id = 0 has the temporal shift. | |
| EXPECT_EQ(frames[0].temporal_id, 0); | |
| EXPECT_EQ(frames[2].temporal_id, 0); | |
| EXPECT_EQ(frames[3].temporal_id, 1); | |
| EXPECT_EQ(frames[5].temporal_id, 0); | |
| EXPECT_EQ(frames[6].temporal_id, 1); | |
| // spatial_id = 1 has single temporal layer. | |
| EXPECT_EQ(frames[1].temporal_id, 0); | |
| EXPECT_EQ(frames[4].temporal_id, 0); | |
| EXPECT_EQ(frames[5].temporal_id, 0); | |
| } | |
| // S1T1 3 | | |
| // / | | |
| // S1T0 1---5+--7 | |
| // | | | |
| // S0T1 | 4| | |
| // | / | | |
| // S0T0 0-2--+6---8 | |
| // Time-> 0 1 2 3 4 5 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, DisableT1LayersAfterFewFrames) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| EXPECT_THAT(frames, SizeIs(6)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/1, /*s1=*/1)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(9)); | |
| // Skip validation before T1 was disabled as that is covered by the test | |
| // where no layers are disabled. | |
| EXPECT_EQ(frames[6].spatial_id, 0); | |
| EXPECT_EQ(frames[7].spatial_id, 1); | |
| EXPECT_EQ(frames[8].spatial_id, 0); | |
| EXPECT_EQ(frames[6].temporal_id, 0); | |
| EXPECT_EQ(frames[7].temporal_id, 0); | |
| EXPECT_EQ(frames[8].temporal_id, 0); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| // S1T1 1 3 | |
| // / / | |
| // S1T0 0---2 | |
| // Time-> 0 1 2 3 4 5 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, DisableS0FromTheStart) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/0, /*s1=*/2)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/4, frames); | |
| EXPECT_THAT(frames, SizeIs(4)); | |
| EXPECT_EQ(frames[0].spatial_id, 1); | |
| EXPECT_EQ(frames[1].spatial_id, 1); | |
| EXPECT_EQ(frames[2].spatial_id, 1); | |
| EXPECT_EQ(frames[3].spatial_id, 1); | |
| EXPECT_EQ(frames[0].temporal_id, 0); | |
| EXPECT_EQ(frames[1].temporal_id, 1); | |
| EXPECT_EQ(frames[2].temporal_id, 0); | |
| EXPECT_EQ(frames[3].temporal_id, 1); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| // S1T1 3 |6 8 | |
| // / / / | |
| // S1T0 1---5+--7 | |
| // | | | |
| // S0T1 | 4| | |
| // | / | | |
| // S0T0 0-2 | | |
| // Time-> 0 1 2 3 4 5 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, DisableS0AfterFewFrames) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| EXPECT_THAT(frames, SizeIs(6)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/0, /*s1=*/2)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(9)); | |
| // Expect frame[6] is delta frame. | |
| EXPECT_THAT(frames[6].frame_diffs, ElementsAre(1)); | |
| // Skip validation before S0 was disabled as that should be covered by | |
| // test where no layers are disabled. | |
| EXPECT_EQ(frames[6].spatial_id, 1); | |
| EXPECT_EQ(frames[7].spatial_id, 1); | |
| EXPECT_EQ(frames[8].spatial_id, 1); | |
| EXPECT_EQ(frames[6].temporal_id, 1); | |
| EXPECT_EQ(frames[7].temporal_id, 0); | |
| EXPECT_EQ(frames[8].temporal_id, 1); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| // S1T1 3| | 8 | |
| // / | | / | |
| // S1T0 1 | |6 | |
| // | | || | |
| // S0T1 | |4|| | |
| // | / || | |
| // S0T0 0-2| |5-7 | |
| // Time-> 0 1 2 3 4 5 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, ReenableS1TriggersKeyFrame) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/2, frames); | |
| EXPECT_THAT(frames, SizeIs(4)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/0)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/1, frames); | |
| EXPECT_THAT(frames, SizeIs(5)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/2)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/2, frames); | |
| ASSERT_THAT(frames, SizeIs(9)); | |
| EXPECT_THAT(frames[4].spatial_id, 0); | |
| EXPECT_THAT(frames[4].temporal_id, 1); | |
| // Expect frame[5] to be a key frame. | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(std::span(frames.data() + 5, 4))); | |
| EXPECT_THAT(frames[5].spatial_id, 0); | |
| EXPECT_THAT(frames[6].spatial_id, 1); | |
| EXPECT_THAT(frames[7].spatial_id, 0); | |
| EXPECT_THAT(frames[8].spatial_id, 1); | |
| // S0 should do temporal shift after the key frame. | |
| EXPECT_THAT(frames[5].temporal_id, 0); | |
| EXPECT_THAT(frames[7].temporal_id, 0); | |
| // No temporal shift for the top spatial layer. | |
| EXPECT_THAT(frames[6].temporal_id, 0); | |
| EXPECT_THAT(frames[8].temporal_id, 1); | |
| } | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, EnableOnlyS0T0FromTheStart) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/1, /*s1=*/0)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(3)); | |
| EXPECT_EQ(frames[0].spatial_id, 0); | |
| EXPECT_EQ(frames[1].spatial_id, 0); | |
| EXPECT_EQ(frames[2].spatial_id, 0); | |
| EXPECT_EQ(frames[0].temporal_id, 0); | |
| EXPECT_EQ(frames[1].temporal_id, 0); | |
| EXPECT_EQ(frames[2].temporal_id, 0); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| // S1T1 3| | |
| // / | | |
| // S1T0 1 | | |
| // | | | |
| // S0T1 | | | |
| // | | | |
| // S0T0 0-2+4-5-6 | |
| // Time-> 0 1 2 3 4 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, EnableOnlyS0T0AfterFewFrames) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/2, frames); | |
| EXPECT_THAT(frames, SizeIs(4)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/1, /*s1=*/0)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(7)); | |
| EXPECT_EQ(frames[4].spatial_id, 0); | |
| EXPECT_EQ(frames[5].spatial_id, 0); | |
| EXPECT_EQ(frames[6].spatial_id, 0); | |
| EXPECT_EQ(frames[4].temporal_id, 0); | |
| EXPECT_EQ(frames[5].temporal_id, 0); | |
| EXPECT_EQ(frames[6].temporal_id, 0); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, EnableOnlyS1T0FromTheStart) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/0, /*s1=*/1)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(3)); | |
| EXPECT_EQ(frames[0].spatial_id, 1); | |
| EXPECT_EQ(frames[1].spatial_id, 1); | |
| EXPECT_EQ(frames[2].spatial_id, 1); | |
| EXPECT_EQ(frames[0].temporal_id, 0); | |
| EXPECT_EQ(frames[1].temporal_id, 0); | |
| EXPECT_EQ(frames[2].temporal_id, 0); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| // S1T1 3| | |
| // / | | |
| // S1T0 1--+4-5-6 | |
| // | | | |
| // S0T1 | | | |
| // | | | |
| // S0T0 0-2| | |
| // Time-> 0 1 2 3 4 | |
| TEST(ScalabilityStructureL2T2KeyShiftTest, EnableOnlyS1T0AfterFewFrames) { | |
| ScalabilityStructureL2T2KeyShift structure; | |
| ScalabilityStructureWrapper wrapper(structure); | |
| std::vector<GenericFrameInfo> frames; | |
| wrapper.GenerateFrames(/*num_temporal_units=*/2, frames); | |
| EXPECT_THAT(frames, SizeIs(4)); | |
| structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/0, /*s1=*/1)); | |
| wrapper.GenerateFrames(/*num_temporal_units=*/3, frames); | |
| ASSERT_THAT(frames, SizeIs(7)); | |
| EXPECT_EQ(frames[4].spatial_id, 1); | |
| EXPECT_EQ(frames[5].spatial_id, 1); | |
| EXPECT_EQ(frames[6].spatial_id, 1); | |
| EXPECT_EQ(frames[4].temporal_id, 0); | |
| EXPECT_EQ(frames[5].temporal_id, 0); | |
| EXPECT_EQ(frames[6].temporal_id, 0); | |
| EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames)); | |
| } | |
| } // namespace | |
| } // namespace webrtc |