blob: 40fecf18120bbc869922aab8481c1c2d347b371d [file] [log] [blame]
/*
* 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 <vector>
#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<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(
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<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