/* * 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 #include "api/array_view.h" #include "api/transport/rtp/dependency_descriptor.h" #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 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 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 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 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 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 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( rtc::MakeArrayView(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 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 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 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 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