blob: e5fa4c4368c8a3593e9993844a739a98d848fd76 [file] [log] [blame]
Danil Chapovalov735e33f2021-02-18 14:39:52 +01001/*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#include "modules/video_coding/svc/scalability_structure_simulcast.h"
11
12#include <utility>
13#include <vector>
14
15#include "absl/base/macros.h"
16#include "api/transport/rtp/dependency_descriptor.h"
17#include "rtc_base/checks.h"
18#include "rtc_base/logging.h"
19
20namespace webrtc {
21namespace {
22
23DecodeTargetIndication
24Dti(int sid, int tid, const ScalableVideoController::LayerFrameConfig& config) {
25 if (sid != config.SpatialId() || tid < config.TemporalId()) {
26 return DecodeTargetIndication::kNotPresent;
27 }
28 if (tid == 0) {
29 RTC_DCHECK_EQ(config.TemporalId(), 0);
30 return DecodeTargetIndication::kSwitch;
31 }
32 if (tid == config.TemporalId()) {
33 return DecodeTargetIndication::kDiscardable;
34 }
35 RTC_DCHECK_GT(tid, config.TemporalId());
36 return DecodeTargetIndication::kSwitch;
37}
38
39} // namespace
40
41constexpr int ScalabilityStructureSimulcast::kMaxNumSpatialLayers;
42constexpr int ScalabilityStructureSimulcast::kMaxNumTemporalLayers;
43
44ScalabilityStructureSimulcast::ScalabilityStructureSimulcast(
45 int num_spatial_layers,
46 int num_temporal_layers)
47 : num_spatial_layers_(num_spatial_layers),
48 num_temporal_layers_(num_temporal_layers),
49 active_decode_targets_(
50 (uint32_t{1} << (num_spatial_layers * num_temporal_layers)) - 1) {
51 RTC_DCHECK_LE(num_spatial_layers, kMaxNumSpatialLayers);
52 RTC_DCHECK_LE(num_temporal_layers, kMaxNumTemporalLayers);
53}
54
55ScalabilityStructureSimulcast::~ScalabilityStructureSimulcast() = default;
56
57ScalableVideoController::StreamLayersConfig
58ScalabilityStructureSimulcast::StreamConfig() const {
59 StreamLayersConfig result;
60 result.num_spatial_layers = num_spatial_layers_;
61 result.num_temporal_layers = num_temporal_layers_;
62 result.scaling_factor_num[num_spatial_layers_ - 1] = 1;
63 result.scaling_factor_den[num_spatial_layers_ - 1] = 1;
64 for (int sid = num_spatial_layers_ - 1; sid > 0; --sid) {
65 result.scaling_factor_num[sid - 1] = 1;
66 result.scaling_factor_den[sid - 1] = 2 * result.scaling_factor_den[sid];
67 }
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020068 result.uses_reference_scaling = false;
Danil Chapovalov735e33f2021-02-18 14:39:52 +010069 return result;
70}
71
72bool ScalabilityStructureSimulcast::TemporalLayerIsActive(int tid) const {
73 if (tid >= num_temporal_layers_) {
74 return false;
75 }
76 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
77 if (DecodeTargetIsActive(sid, tid)) {
78 return true;
79 }
80 }
81 return false;
82}
83
84ScalabilityStructureSimulcast::FramePattern
85ScalabilityStructureSimulcast::NextPattern() const {
86 switch (last_pattern_) {
87 case kNone:
88 case kDeltaT2B:
89 return kDeltaT0;
90 case kDeltaT2A:
91 if (TemporalLayerIsActive(1)) {
92 return kDeltaT1;
93 }
94 return kDeltaT0;
95 case kDeltaT1:
96 if (TemporalLayerIsActive(2)) {
97 return kDeltaT2B;
98 }
99 return kDeltaT0;
100 case kDeltaT0:
101 if (TemporalLayerIsActive(2)) {
102 return kDeltaT2A;
103 }
104 if (TemporalLayerIsActive(1)) {
105 return kDeltaT1;
106 }
107 return kDeltaT0;
108 }
Artem Titovd3251962021-11-15 16:57:07 +0100109 RTC_DCHECK_NOTREACHED();
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100110 return kDeltaT0;
111}
112
113std::vector<ScalableVideoController::LayerFrameConfig>
114ScalabilityStructureSimulcast::NextFrameConfig(bool restart) {
115 std::vector<LayerFrameConfig> configs;
116 if (active_decode_targets_.none()) {
117 last_pattern_ = kNone;
118 return configs;
119 }
120 configs.reserve(num_spatial_layers_);
121
122 if (last_pattern_ == kNone || restart) {
123 can_reference_t0_frame_for_spatial_id_.reset();
124 last_pattern_ = kNone;
125 }
126 FramePattern current_pattern = NextPattern();
127
128 switch (current_pattern) {
129 case kDeltaT0:
130 // Disallow temporal references cross T0 on higher temporal layers.
131 can_reference_t1_frame_for_spatial_id_.reset();
132 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
133 if (!DecodeTargetIsActive(sid, /*tid=*/0)) {
134 // Next frame from the spatial layer `sid` shouldn't depend on
135 // potentially old previous frame from the spatial layer `sid`.
136 can_reference_t0_frame_for_spatial_id_.reset(sid);
137 continue;
138 }
139 configs.emplace_back();
140 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200141 config.Id(current_pattern).S(sid).T(0);
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100142
143 if (can_reference_t0_frame_for_spatial_id_[sid]) {
144 config.ReferenceAndUpdate(BufferIndex(sid, /*tid=*/0));
145 } else {
146 config.Keyframe().Update(BufferIndex(sid, /*tid=*/0));
147 }
148 can_reference_t0_frame_for_spatial_id_.set(sid);
149 }
150 break;
151 case kDeltaT1:
152 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
153 if (!DecodeTargetIsActive(sid, /*tid=*/1) ||
154 !can_reference_t0_frame_for_spatial_id_[sid]) {
155 continue;
156 }
157 configs.emplace_back();
158 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200159 config.Id(current_pattern)
160 .S(sid)
161 .T(1)
162 .Reference(BufferIndex(sid, /*tid=*/0));
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100163 // Save frame only if there is a higher temporal layer that may need it.
164 if (num_temporal_layers_ > 2) {
165 config.Update(BufferIndex(sid, /*tid=*/1));
166 }
167 }
168 break;
169 case kDeltaT2A:
170 case kDeltaT2B:
171 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
172 if (!DecodeTargetIsActive(sid, /*tid=*/2) ||
173 !can_reference_t0_frame_for_spatial_id_[sid]) {
174 continue;
175 }
176 configs.emplace_back();
177 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200178 config.Id(current_pattern).S(sid).T(2);
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100179 if (can_reference_t1_frame_for_spatial_id_[sid]) {
180 config.Reference(BufferIndex(sid, /*tid=*/1));
181 } else {
182 config.Reference(BufferIndex(sid, /*tid=*/0));
183 }
184 }
185 break;
186 case kNone:
Artem Titovd3251962021-11-15 16:57:07 +0100187 RTC_DCHECK_NOTREACHED();
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100188 break;
189 }
190
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100191 return configs;
192}
193
194GenericFrameInfo ScalabilityStructureSimulcast::OnEncodeDone(
195 const LayerFrameConfig& config) {
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200196 last_pattern_ = static_cast<FramePattern>(config.Id());
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100197 if (config.TemporalId() == 1) {
198 can_reference_t1_frame_for_spatial_id_.set(config.SpatialId());
199 }
200 GenericFrameInfo frame_info;
201 frame_info.spatial_id = config.SpatialId();
202 frame_info.temporal_id = config.TemporalId();
203 frame_info.encoder_buffers = config.Buffers();
204 frame_info.decode_target_indications.reserve(num_spatial_layers_ *
205 num_temporal_layers_);
206 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
207 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
208 frame_info.decode_target_indications.push_back(Dti(sid, tid, config));
209 }
210 }
211 frame_info.part_of_chain.assign(num_spatial_layers_, false);
212 if (config.TemporalId() == 0) {
213 frame_info.part_of_chain[config.SpatialId()] = true;
214 }
215 frame_info.active_decode_targets = active_decode_targets_;
216 return frame_info;
217}
218
219void ScalabilityStructureSimulcast::OnRatesUpdated(
220 const VideoBitrateAllocation& bitrates) {
221 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
222 // Enable/disable spatial layers independetely.
223 bool active = true;
224 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
225 // To enable temporal layer, require bitrates for lower temporal layers.
226 active = active && bitrates.GetBitrate(sid, tid) > 0;
227 SetDecodeTargetIsActive(sid, tid, active);
228 }
229 }
230}
231
232FrameDependencyStructure ScalabilityStructureS2T1::DependencyStructure() const {
233 FrameDependencyStructure structure;
234 structure.num_decode_targets = 2;
235 structure.num_chains = 2;
236 structure.decode_target_protected_by_chain = {0, 1};
237 structure.templates.resize(4);
238 structure.templates[0].S(0).Dtis("S-").ChainDiffs({2, 1}).FrameDiffs({2});
239 structure.templates[1].S(0).Dtis("S-").ChainDiffs({0, 0});
240 structure.templates[2].S(1).Dtis("-S").ChainDiffs({1, 2}).FrameDiffs({2});
241 structure.templates[3].S(1).Dtis("-S").ChainDiffs({1, 0});
242 return structure;
243}
244
245FrameDependencyStructure ScalabilityStructureS3T3::DependencyStructure() const {
246 FrameDependencyStructure structure;
247 structure.num_decode_targets = 9;
248 structure.num_chains = 3;
249 structure.decode_target_protected_by_chain = {0, 0, 0, 1, 1, 1, 2, 2, 2};
250 auto& t = structure.templates;
251 t.resize(15);
252 // Templates are shown in the order frames following them appear in the
253 // stream, but in `structure.templates` array templates are sorted by
254 // (`spatial_id`, `temporal_id`) since that is a dependency descriptor
255 // requirement. Indexes are written in hex for nicer alignment.
256 t[0x1].S(0).T(0).Dtis("SSS------").ChainDiffs({0, 0, 0});
257 t[0x6].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 0, 0});
258 t[0xB].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 0});
259 t[0x3].S(0).T(2).Dtis("--D------").ChainDiffs({3, 2, 1}).FrameDiffs({3});
260 t[0x8].S(1).T(2).Dtis("-----D---").ChainDiffs({4, 3, 2}).FrameDiffs({3});
261 t[0xD].S(2).T(2).Dtis("--------D").ChainDiffs({5, 4, 3}).FrameDiffs({3});
262 t[0x2].S(0).T(1).Dtis("-DS------").ChainDiffs({6, 5, 4}).FrameDiffs({6});
263 t[0x7].S(1).T(1).Dtis("----DS---").ChainDiffs({7, 6, 5}).FrameDiffs({6});
264 t[0xC].S(2).T(1).Dtis("-------DS").ChainDiffs({8, 7, 6}).FrameDiffs({6});
265 t[0x4].S(0).T(2).Dtis("--D------").ChainDiffs({9, 8, 7}).FrameDiffs({3});
266 t[0x9].S(1).T(2).Dtis("-----D---").ChainDiffs({10, 9, 8}).FrameDiffs({3});
267 t[0xE].S(2).T(2).Dtis("--------D").ChainDiffs({11, 10, 9}).FrameDiffs({3});
268 t[0x0].S(0).T(0).Dtis("SSS------").ChainDiffs({12, 11, 10}).FrameDiffs({12});
269 t[0x5].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 12, 11}).FrameDiffs({12});
270 t[0xA].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 12}).FrameDiffs({12});
271 return structure;
272}
273
274} // namespace webrtc