Add layer skipping to L2T2_KEY_SHIFT structure
Bug: None Change-Id: Iba019a999cb1812eee12bfe54c2f9ec9ebfa248f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/189965 Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32487}
This commit is contained in:

committed by
Commit Bot

parent
f01bd6c266
commit
71002a226a
@ -73,6 +73,7 @@ if (rtc_include_tests) {
|
||||
testonly = true
|
||||
sources = [
|
||||
"scalability_structure_key_svc_unittest.cc",
|
||||
"scalability_structure_l2t2_key_shift_unittest.cc",
|
||||
"scalability_structure_l3t3_unittest.cc",
|
||||
"scalability_structure_test_helpers.cc",
|
||||
"scalability_structure_test_helpers.h",
|
||||
|
@ -20,21 +20,28 @@
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr auto kNotPresent = DecodeTargetIndication::kNotPresent;
|
||||
constexpr auto kDiscardable = DecodeTargetIndication::kDiscardable;
|
||||
constexpr auto kSwitch = DecodeTargetIndication::kSwitch;
|
||||
DecodeTargetIndication
|
||||
Dti(int sid, int tid, const ScalableVideoController::LayerFrameConfig& config) {
|
||||
if (config.IsKeyframe()) {
|
||||
RTC_DCHECK_EQ(config.TemporalId(), 0);
|
||||
return sid < config.SpatialId() ? DecodeTargetIndication::kNotPresent
|
||||
: DecodeTargetIndication::kSwitch;
|
||||
}
|
||||
|
||||
constexpr DecodeTargetIndication kDtis[6][4] = {
|
||||
{kSwitch, kSwitch, kSwitch, kSwitch}, // kKey, S0T0
|
||||
{kNotPresent, kNotPresent, kSwitch, kSwitch}, // kKey, S1T0
|
||||
{kSwitch, kSwitch, kNotPresent, kNotPresent}, // kDelta0, S0T0
|
||||
{kNotPresent, kNotPresent, kNotPresent, kDiscardable}, // kDelta0, S1T1
|
||||
{kNotPresent, kDiscardable, kNotPresent, kNotPresent}, // kDelta1, S0T1
|
||||
{kNotPresent, kNotPresent, kSwitch, kSwitch}, // kDelta1, S1T0
|
||||
};
|
||||
if (sid != config.SpatialId() || tid < config.TemporalId()) {
|
||||
return DecodeTargetIndication::kNotPresent;
|
||||
}
|
||||
if (tid == config.TemporalId() && tid > 0) {
|
||||
return DecodeTargetIndication::kDiscardable;
|
||||
}
|
||||
return DecodeTargetIndication::kSwitch;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr int ScalabilityStructureL2T2KeyShift::kNumSpatialLayers;
|
||||
constexpr int ScalabilityStructureL2T2KeyShift::kNumTemporalLayers;
|
||||
|
||||
ScalabilityStructureL2T2KeyShift::~ScalabilityStructureL2T2KeyShift() = default;
|
||||
|
||||
ScalableVideoController::StreamLayersConfig
|
||||
@ -65,52 +72,80 @@ FrameDependencyStructure ScalabilityStructureL2T2KeyShift::DependencyStructure()
|
||||
return structure;
|
||||
}
|
||||
|
||||
ScalableVideoController::LayerFrameConfig
|
||||
ScalabilityStructureL2T2KeyShift::KeyFrameConfig() const {
|
||||
return LayerFrameConfig().Id(0).Keyframe().S(0).T(0).Update(0);
|
||||
}
|
||||
|
||||
std::vector<ScalableVideoController::LayerFrameConfig>
|
||||
ScalabilityStructureL2T2KeyShift::NextFrameConfig(bool restart) {
|
||||
std::vector<LayerFrameConfig> configs;
|
||||
configs.reserve(2);
|
||||
if (restart) {
|
||||
next_pattern_ = kKey;
|
||||
}
|
||||
std::vector<LayerFrameConfig> result(2);
|
||||
|
||||
// Buffer0 keeps latest S0T0 frame,
|
||||
// Buffer1 keeps latest S1T0 frame.
|
||||
switch (next_pattern_) {
|
||||
case kKey:
|
||||
result[0] = KeyFrameConfig();
|
||||
result[1].Id(1).S(1).T(0).Reference(0).Update(1);
|
||||
if (DecodeTargetIsActive(/*sid=*/0, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(0).T(0).Update(0).Keyframe();
|
||||
}
|
||||
if (DecodeTargetIsActive(/*sid=*/1, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(1).T(0).Update(1);
|
||||
if (DecodeTargetIsActive(/*sid=*/0, /*tid=*/0)) {
|
||||
configs.back().Reference(0);
|
||||
} else {
|
||||
configs.back().Keyframe();
|
||||
}
|
||||
}
|
||||
next_pattern_ = kDelta0;
|
||||
break;
|
||||
case kDelta0:
|
||||
result[0].Id(2).S(0).T(0).ReferenceAndUpdate(0);
|
||||
result[1].Id(3).S(1).T(1).Reference(1);
|
||||
if (DecodeTargetIsActive(/*sid=*/0, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(0).T(0).ReferenceAndUpdate(0);
|
||||
}
|
||||
if (DecodeTargetIsActive(/*sid=*/1, /*tid=*/1)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(1).T(1).Reference(1);
|
||||
}
|
||||
if (configs.empty() && DecodeTargetIsActive(/*sid=*/1, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(1).T(0).ReferenceAndUpdate(1);
|
||||
}
|
||||
next_pattern_ = kDelta1;
|
||||
break;
|
||||
case kDelta1:
|
||||
result[0].Id(4).S(0).T(1).Reference(0);
|
||||
result[1].Id(5).S(1).T(0).ReferenceAndUpdate(1);
|
||||
if (DecodeTargetIsActive(/*sid=*/0, /*tid=*/1)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(0).T(1).Reference(0);
|
||||
}
|
||||
if (DecodeTargetIsActive(/*sid=*/1, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(1).T(0).ReferenceAndUpdate(1);
|
||||
}
|
||||
if (configs.empty() && DecodeTargetIsActive(/*sid=*/0, /*tid=*/0)) {
|
||||
configs.emplace_back();
|
||||
configs.back().S(0).T(0).ReferenceAndUpdate(0);
|
||||
}
|
||||
next_pattern_ = kDelta0;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
|
||||
RTC_DCHECK(!configs.empty() || active_decode_targets_.none());
|
||||
return configs;
|
||||
}
|
||||
|
||||
GenericFrameInfo ScalabilityStructureL2T2KeyShift::OnEncodeDone(
|
||||
const LayerFrameConfig& config) {
|
||||
RTC_CHECK_GE(config.Id(), 0);
|
||||
RTC_CHECK_LT(config.Id(), ABSL_ARRAYSIZE(kDtis));
|
||||
|
||||
GenericFrameInfo frame_info;
|
||||
frame_info.spatial_id = config.SpatialId();
|
||||
frame_info.temporal_id = config.TemporalId();
|
||||
frame_info.encoder_buffers = config.Buffers();
|
||||
int config_id = config.IsKeyframe() ? 0 : config.Id();
|
||||
frame_info.decode_target_indications.assign(std::begin(kDtis[config_id]),
|
||||
std::end(kDtis[config_id]));
|
||||
for (int sid = 0; sid < kNumSpatialLayers; ++sid) {
|
||||
for (int tid = 0; tid < kNumTemporalLayers; ++tid) {
|
||||
frame_info.decode_target_indications.push_back(Dti(sid, tid, config));
|
||||
}
|
||||
}
|
||||
if (config.IsKeyframe()) {
|
||||
frame_info.part_of_chain = {true, true};
|
||||
} else if (config.TemporalId() == 0) {
|
||||
@ -122,4 +157,20 @@ GenericFrameInfo ScalabilityStructureL2T2KeyShift::OnEncodeDone(
|
||||
return frame_info;
|
||||
}
|
||||
|
||||
void ScalabilityStructureL2T2KeyShift::OnRatesUpdated(
|
||||
const VideoBitrateAllocation& bitrates) {
|
||||
for (int sid = 0; sid < kNumSpatialLayers; ++sid) {
|
||||
// Enable/disable spatial layers independetely.
|
||||
bool active = bitrates.GetBitrate(sid, /*tid=*/0) > 0;
|
||||
if (!DecodeTargetIsActive(sid, /*tid=*/0) && active) {
|
||||
// Key frame is required to reenable any spatial layer.
|
||||
next_pattern_ = kKey;
|
||||
}
|
||||
|
||||
SetDecodeTargetIsActive(sid, /*tid=*/0, active);
|
||||
SetDecodeTargetIsActive(sid, /*tid=*/1,
|
||||
active && bitrates.GetBitrate(sid, /*tid=*/1) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "api/transport/rtp/dependency_descriptor.h"
|
||||
#include "api/video/video_bitrate_allocation.h"
|
||||
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
|
||||
#include "modules/video_coding/svc/scalable_video_controller.h"
|
||||
|
||||
@ -35,6 +36,7 @@ class ScalabilityStructureL2T2KeyShift : public ScalableVideoController {
|
||||
|
||||
std::vector<LayerFrameConfig> NextFrameConfig(bool restart) override;
|
||||
GenericFrameInfo OnEncodeDone(const LayerFrameConfig& config) override;
|
||||
void OnRatesUpdated(const VideoBitrateAllocation& bitrates) override;
|
||||
|
||||
private:
|
||||
enum FramePattern {
|
||||
@ -42,9 +44,19 @@ class ScalabilityStructureL2T2KeyShift : public ScalableVideoController {
|
||||
kDelta0,
|
||||
kDelta1,
|
||||
};
|
||||
LayerFrameConfig KeyFrameConfig() const;
|
||||
|
||||
static constexpr int kNumSpatialLayers = 2;
|
||||
static constexpr int kNumTemporalLayers = 2;
|
||||
|
||||
bool DecodeTargetIsActive(int sid, int tid) const {
|
||||
return active_decode_targets_[sid * kNumTemporalLayers + tid];
|
||||
}
|
||||
void SetDecodeTargetIsActive(int sid, int tid, bool value) {
|
||||
active_decode_targets_.set(sid * kNumTemporalLayers + tid, value);
|
||||
}
|
||||
|
||||
FramePattern next_pattern_ = kKey;
|
||||
std::bitset<32> active_decode_targets_ = 0b1111;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* 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
|
@ -250,11 +250,7 @@ TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(danilchap): Merge with ScalabilityStructureTest when SetRates
|
||||
// implemented for all tested structures.
|
||||
class ScalabilityStructureSetRatesTest : public ScalabilityStructureTest {};
|
||||
|
||||
TEST_P(ScalabilityStructureSetRatesTest, ProduceNoFrameForDisabledLayers) {
|
||||
TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
|
||||
std::unique_ptr<ScalableVideoController> svc_controller =
|
||||
CreateScalabilityStructure(GetParam().name);
|
||||
ScalableVideoController::StreamLayersConfig structure =
|
||||
@ -311,24 +307,5 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
return info.param.name;
|
||||
});
|
||||
|
||||
// TODO(danilchap): Merge with ScalabilityStructureTest when the functionality
|
||||
// is implemented for all tested structures.
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Svc,
|
||||
ScalabilityStructureSetRatesTest,
|
||||
Values(SvcTestParam{"L1T2", /*num_temporal_units=*/4},
|
||||
SvcTestParam{"L1T3", /*num_temporal_units=*/8},
|
||||
SvcTestParam{"L2T1", /*num_temporal_units=*/3},
|
||||
SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
|
||||
SvcTestParam{"L2T2", /*num_temporal_units=*/4},
|
||||
SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
|
||||
SvcTestParam{"L3T1", /*num_temporal_units=*/3},
|
||||
SvcTestParam{"L3T3", /*num_temporal_units=*/8},
|
||||
SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8},
|
||||
SvcTestParam{"S2T1", /*num_temporal_units=*/3}),
|
||||
[](const testing::TestParamInfo<SvcTestParam>& info) {
|
||||
return info.param.name;
|
||||
});
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc
|
||||
|
Reference in New Issue
Block a user