blob: 13751daea68aca78cdbf5b067c963349f3c2c308 [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();
140 config.S(sid).T(0);
141
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();
158 config.S(sid).T(1).Reference(BufferIndex(sid, /*tid=*/0));
159 // Save frame only if there is a higher temporal layer that may need it.
160 if (num_temporal_layers_ > 2) {
161 config.Update(BufferIndex(sid, /*tid=*/1));
162 }
163 }
164 break;
165 case kDeltaT2A:
166 case kDeltaT2B:
167 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
168 if (!DecodeTargetIsActive(sid, /*tid=*/2) ||
169 !can_reference_t0_frame_for_spatial_id_[sid]) {
170 continue;
171 }
172 configs.emplace_back();
173 ScalableVideoController::LayerFrameConfig& config = configs.back();
174 config.S(sid).T(2);
175 if (can_reference_t1_frame_for_spatial_id_[sid]) {
176 config.Reference(BufferIndex(sid, /*tid=*/1));
177 } else {
178 config.Reference(BufferIndex(sid, /*tid=*/0));
179 }
180 }
181 break;
182 case kNone:
183 RTC_NOTREACHED();
184 break;
185 }
186
187 last_pattern_ = current_pattern;
188 return configs;
189}
190
191GenericFrameInfo ScalabilityStructureSimulcast::OnEncodeDone(
192 const LayerFrameConfig& config) {
193 if (config.TemporalId() == 1) {
194 can_reference_t1_frame_for_spatial_id_.set(config.SpatialId());
195 }
196 GenericFrameInfo frame_info;
197 frame_info.spatial_id = config.SpatialId();
198 frame_info.temporal_id = config.TemporalId();
199 frame_info.encoder_buffers = config.Buffers();
200 frame_info.decode_target_indications.reserve(num_spatial_layers_ *
201 num_temporal_layers_);
202 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
203 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
204 frame_info.decode_target_indications.push_back(Dti(sid, tid, config));
205 }
206 }
207 frame_info.part_of_chain.assign(num_spatial_layers_, false);
208 if (config.TemporalId() == 0) {
209 frame_info.part_of_chain[config.SpatialId()] = true;
210 }
211 frame_info.active_decode_targets = active_decode_targets_;
212 return frame_info;
213}
214
215void ScalabilityStructureSimulcast::OnRatesUpdated(
216 const VideoBitrateAllocation& bitrates) {
217 for (int sid = 0; sid < num_spatial_layers_; ++sid) {
218 // Enable/disable spatial layers independetely.
219 bool active = true;
220 for (int tid = 0; tid < num_temporal_layers_; ++tid) {
221 // To enable temporal layer, require bitrates for lower temporal layers.
222 active = active && bitrates.GetBitrate(sid, tid) > 0;
223 SetDecodeTargetIsActive(sid, tid, active);
224 }
225 }
226}
227
228FrameDependencyStructure ScalabilityStructureS2T1::DependencyStructure() const {
229 FrameDependencyStructure structure;
230 structure.num_decode_targets = 2;
231 structure.num_chains = 2;
232 structure.decode_target_protected_by_chain = {0, 1};
233 structure.templates.resize(4);
234 structure.templates[0].S(0).Dtis("S-").ChainDiffs({2, 1}).FrameDiffs({2});
235 structure.templates[1].S(0).Dtis("S-").ChainDiffs({0, 0});
236 structure.templates[2].S(1).Dtis("-S").ChainDiffs({1, 2}).FrameDiffs({2});
237 structure.templates[3].S(1).Dtis("-S").ChainDiffs({1, 0});
238 return structure;
239}
240
241FrameDependencyStructure ScalabilityStructureS3T3::DependencyStructure() const {
242 FrameDependencyStructure structure;
243 structure.num_decode_targets = 9;
244 structure.num_chains = 3;
245 structure.decode_target_protected_by_chain = {0, 0, 0, 1, 1, 1, 2, 2, 2};
246 auto& t = structure.templates;
247 t.resize(15);
248 // Templates are shown in the order frames following them appear in the
249 // stream, but in `structure.templates` array templates are sorted by
250 // (`spatial_id`, `temporal_id`) since that is a dependency descriptor
251 // requirement. Indexes are written in hex for nicer alignment.
252 t[0x1].S(0).T(0).Dtis("SSS------").ChainDiffs({0, 0, 0});
253 t[0x6].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 0, 0});
254 t[0xB].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 0});
255 t[0x3].S(0).T(2).Dtis("--D------").ChainDiffs({3, 2, 1}).FrameDiffs({3});
256 t[0x8].S(1).T(2).Dtis("-----D---").ChainDiffs({4, 3, 2}).FrameDiffs({3});
257 t[0xD].S(2).T(2).Dtis("--------D").ChainDiffs({5, 4, 3}).FrameDiffs({3});
258 t[0x2].S(0).T(1).Dtis("-DS------").ChainDiffs({6, 5, 4}).FrameDiffs({6});
259 t[0x7].S(1).T(1).Dtis("----DS---").ChainDiffs({7, 6, 5}).FrameDiffs({6});
260 t[0xC].S(2).T(1).Dtis("-------DS").ChainDiffs({8, 7, 6}).FrameDiffs({6});
261 t[0x4].S(0).T(2).Dtis("--D------").ChainDiffs({9, 8, 7}).FrameDiffs({3});
262 t[0x9].S(1).T(2).Dtis("-----D---").ChainDiffs({10, 9, 8}).FrameDiffs({3});
263 t[0xE].S(2).T(2).Dtis("--------D").ChainDiffs({11, 10, 9}).FrameDiffs({3});
264 t[0x0].S(0).T(0).Dtis("SSS------").ChainDiffs({12, 11, 10}).FrameDiffs({12});
265 t[0x5].S(1).T(0).Dtis("---SSS---").ChainDiffs({1, 12, 11}).FrameDiffs({12});
266 t[0xA].S(2).T(0).Dtis("------SSS").ChainDiffs({2, 1, 12}).FrameDiffs({12});
267 return structure;
268}
269
270} // namespace webrtc