blob: c236066736369a674314d81c666e31d86d94d267 [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 }
68 return result;
69}
70
71bool ScalabilityStructureSimulcast::TemporalLayerIsActive(int tid) const {
72 if (tid >= num_temporal_layers_) {
73 return false;
74 }
75 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
76 if (DecodeTargetIsActive(sid, tid)) {
77 return true;
78 }
79 }
80 return false;
81}
82
83ScalabilityStructureSimulcast::FramePattern
84ScalabilityStructureSimulcast::NextPattern() const {
85 switch (last_pattern_) {
86 case kNone:
87 case kDeltaT2B:
88 return kDeltaT0;
89 case kDeltaT2A:
90 if (TemporalLayerIsActive(1)) {
91 return kDeltaT1;
92 }
93 return kDeltaT0;
94 case kDeltaT1:
95 if (TemporalLayerIsActive(2)) {
96 return kDeltaT2B;
97 }
98 return kDeltaT0;
99 case kDeltaT0:
100 if (TemporalLayerIsActive(2)) {
101 return kDeltaT2A;
102 }
103 if (TemporalLayerIsActive(1)) {
104 return kDeltaT1;
105 }
106 return kDeltaT0;
107 }
108 RTC_NOTREACHED();
109 return kDeltaT0;
110}
111
112std::vector<ScalableVideoController::LayerFrameConfig>
113ScalabilityStructureSimulcast::NextFrameConfig(bool restart) {
114 std::vector<LayerFrameConfig> configs;
115 if (active_decode_targets_.none()) {
116 last_pattern_ = kNone;
117 return configs;
118 }
119 configs.reserve(num_spatial_layers_);
120
121 if (last_pattern_ == kNone || restart) {
122 can_reference_t0_frame_for_spatial_id_.reset();
123 last_pattern_ = kNone;
124 }
125 FramePattern current_pattern = NextPattern();
126
127 switch (current_pattern) {
128 case kDeltaT0:
129 // Disallow temporal references cross T0 on higher temporal layers.
130 can_reference_t1_frame_for_spatial_id_.reset();
131 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
132 if (!DecodeTargetIsActive(sid, /*tid=*/0)) {
133 // Next frame from the spatial layer `sid` shouldn't depend on
134 // potentially old previous frame from the spatial layer `sid`.
135 can_reference_t0_frame_for_spatial_id_.reset(sid);
136 continue;
137 }
138 configs.emplace_back();
139 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200140 config.Id(current_pattern).S(sid).T(0);
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100141
142 if (can_reference_t0_frame_for_spatial_id_[sid]) {
143 config.ReferenceAndUpdate(BufferIndex(sid, /*tid=*/0));
144 } else {
145 config.Keyframe().Update(BufferIndex(sid, /*tid=*/0));
146 }
147 can_reference_t0_frame_for_spatial_id_.set(sid);
148 }
149 break;
150 case kDeltaT1:
151 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
152 if (!DecodeTargetIsActive(sid, /*tid=*/1) ||
153 !can_reference_t0_frame_for_spatial_id_[sid]) {
154 continue;
155 }
156 configs.emplace_back();
157 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200158 config.Id(current_pattern)
159 .S(sid)
160 .T(1)
161 .Reference(BufferIndex(sid, /*tid=*/0));
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100162 // Save frame only if there is a higher temporal layer that may need it.
163 if (num_temporal_layers_ > 2) {
164 config.Update(BufferIndex(sid, /*tid=*/1));
165 }
166 }
167 break;
168 case kDeltaT2A:
169 case kDeltaT2B:
170 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
171 if (!DecodeTargetIsActive(sid, /*tid=*/2) ||
172 !can_reference_t0_frame_for_spatial_id_[sid]) {
173 continue;
174 }
175 configs.emplace_back();
176 ScalableVideoController::LayerFrameConfig& config = configs.back();
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200177 config.Id(current_pattern).S(sid).T(2);
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100178 if (can_reference_t1_frame_for_spatial_id_[sid]) {
179 config.Reference(BufferIndex(sid, /*tid=*/1));
180 } else {
181 config.Reference(BufferIndex(sid, /*tid=*/0));
182 }
183 }
184 break;
185 case kNone:
186 RTC_NOTREACHED();
187 break;
188 }
189
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100190 return configs;
191}
192
193GenericFrameInfo ScalabilityStructureSimulcast::OnEncodeDone(
194 const LayerFrameConfig& config) {
Danil Chapovalove7b752b2021-04-21 14:35:54 +0200195 last_pattern_ = static_cast<FramePattern>(config.Id());
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100196 if (config.TemporalId() == 1) {
197 can_reference_t1_frame_for_spatial_id_.set(config.SpatialId());
198 }
199 GenericFrameInfo frame_info;
200 frame_info.spatial_id = config.SpatialId();
201 frame_info.temporal_id = config.TemporalId();
202 frame_info.encoder_buffers = config.Buffers();
203 frame_info.decode_target_indications.reserve(num_spatial_layers_ *
204 num_temporal_layers_);
205 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
206 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
207 frame_info.decode_target_indications.push_back(Dti(sid, tid, config));
208 }
209 }
210 frame_info.part_of_chain.assign(num_spatial_layers_, false);
211 if (config.TemporalId() == 0) {
212 frame_info.part_of_chain[config.SpatialId()] = true;
213 }
214 frame_info.active_decode_targets = active_decode_targets_;
215 return frame_info;
216}
217
218void ScalabilityStructureSimulcast::OnRatesUpdated(
219 const VideoBitrateAllocation& bitrates) {
220 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
221 // Enable/disable spatial layers independetely.
222 bool active = true;
223 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
224 // To enable temporal layer, require bitrates for lower temporal layers.
225 active = active && bitrates.GetBitrate(sid, tid) > 0;
226 SetDecodeTargetIsActive(sid, tid, active);
227 }
228 }
229}
230
231FrameDependencyStructure ScalabilityStructureS2T1::DependencyStructure() const {
232 FrameDependencyStructure structure;
233 structure.num_decode_targets = 2;
234 structure.num_chains = 2;
235 structure.decode_target_protected_by_chain = {0, 1};
236 structure.templates.resize(4);
237 structure.templates[0].S(0).Dtis("S-").ChainDiffs({2, 1}).FrameDiffs({2});
238 structure.templates[1].S(0).Dtis("S-").ChainDiffs({0, 0});
239 structure.templates[2].S(1).Dtis("-S").ChainDiffs({1, 2}).FrameDiffs({2});
240 structure.templates[3].S(1).Dtis("-S").ChainDiffs({1, 0});
241 return structure;
242}
243
244FrameDependencyStructure ScalabilityStructureS3T3::DependencyStructure() const {
245 FrameDependencyStructure structure;
246 structure.num_decode_targets = 9;
247 structure.num_chains = 3;
248 structure.decode_target_protected_by_chain = {0, 0, 0, 1, 1, 1, 2, 2, 2};
249 auto& t = structure.templates;
250 t.resize(15);
251 // Templates are shown in the order frames following them appear in the
252 // stream, but in `structure.templates` array templates are sorted by
253 // (`spatial_id`, `temporal_id`) since that is a dependency descriptor
254 // requirement. Indexes are written in hex for nicer alignment.
255 t[0x1].S(0).T(0).Dtis("SSS------").ChainDiffs({0, 0, 0});
256 t[0x6].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 0, 0});
257 t[0xB].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 0});
258 t[0x3].S(0).T(2).Dtis("--D------").ChainDiffs({3, 2, 1}).FrameDiffs({3});
259 t[0x8].S(1).T(2).Dtis("-----D---").ChainDiffs({4, 3, 2}).FrameDiffs({3});
260 t[0xD].S(2).T(2).Dtis("--------D").ChainDiffs({5, 4, 3}).FrameDiffs({3});
261 t[0x2].S(0).T(1).Dtis("-DS------").ChainDiffs({6, 5, 4}).FrameDiffs({6});
262 t[0x7].S(1).T(1).Dtis("----DS---").ChainDiffs({7, 6, 5}).FrameDiffs({6});
263 t[0xC].S(2).T(1).Dtis("-------DS").ChainDiffs({8, 7, 6}).FrameDiffs({6});
264 t[0x4].S(0).T(2).Dtis("--D------").ChainDiffs({9, 8, 7}).FrameDiffs({3});
265 t[0x9].S(1).T(2).Dtis("-----D---").ChainDiffs({10, 9, 8}).FrameDiffs({3});
266 t[0xE].S(2).T(2).Dtis("--------D").ChainDiffs({11, 10, 9}).FrameDiffs({3});
267 t[0x0].S(0).T(0).Dtis("SSS------").ChainDiffs({12, 11, 10}).FrameDiffs({12});
268 t[0x5].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 12, 11}).FrameDiffs({12});
269 t[0xA].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 12}).FrameDiffs({12});
270 return structure;
271}
272
273} // namespace webrtc