1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2 *
3 * Use of this source code is governed by a BSD-style license
4 * that can be found in the LICENSE file in the root of the source
5 * tree. An additional intellectual property rights grant can be found
6 * in the file PATENTS. All contributing project authors may
7 * be found in the AUTHORS file in the root of the source tree.
8 */
9
10 #include "modules/video_coding/codecs/vp8/default_temporal_layers.h"
11
12 #include <stdlib.h>
13
14 #include <algorithm>
15 #include <array>
16 #include <memory>
17 #include <set>
18 #include <utility>
19 #include <vector>
20
21 #include "modules/video_coding/include/video_codec_interface.h"
22 #include "rtc_base/arraysize.h"
23 #include "rtc_base/checks.h"
24 #include "rtc_base/logging.h"
25 #include "system_wrappers/include/field_trial.h"
26
27 namespace webrtc {
28 DefaultTemporalLayers::PendingFrame::PendingFrame() = default;
PendingFrame(uint32_t timestamp,bool expired,uint8_t updated_buffers_mask,const DependencyInfo & dependency_info)29 DefaultTemporalLayers::PendingFrame::PendingFrame(
30 uint32_t timestamp,
31 bool expired,
32 uint8_t updated_buffers_mask,
33 const DependencyInfo& dependency_info)
34 : timestamp(timestamp),
35 expired(expired),
36 updated_buffer_mask(updated_buffers_mask),
37 dependency_info(dependency_info) {}
38
39 namespace {
40 using BufferFlags = Vp8FrameConfig::BufferFlags;
41 using FreezeEntropy = Vp8FrameConfig::FreezeEntropy;
42 using Vp8BufferReference = Vp8FrameConfig::Vp8BufferReference;
43
44 constexpr BufferFlags kNone = BufferFlags::kNone;
45 constexpr BufferFlags kReference = BufferFlags::kReference;
46 constexpr BufferFlags kUpdate = BufferFlags::kUpdate;
47 constexpr BufferFlags kReferenceAndUpdate = BufferFlags::kReferenceAndUpdate;
48 constexpr FreezeEntropy kFreezeEntropy = FreezeEntropy::kFreezeEntropy;
49
50 static constexpr uint8_t kUninitializedPatternIndex =
51 std::numeric_limits<uint8_t>::max();
52 static constexpr std::array<Vp8BufferReference, 3> kAllBuffers = {
53 {Vp8BufferReference::kLast, Vp8BufferReference::kGolden,
54 Vp8BufferReference::kAltref}};
55
GetTemporalIds(size_t num_layers)56 std::vector<unsigned int> GetTemporalIds(size_t num_layers) {
57 switch (num_layers) {
58 case 1:
59 // Temporal layer structure (single layer):
60 // 0 0 0 0 ...
61 return {0};
62 case 2:
63 // Temporal layer structure:
64 // 1 1 ...
65 // 0 0 ...
66 return {0, 1};
67 case 3:
68 // Temporal layer structure:
69 // 2 2 2 2 ...
70 // 1 1 ...
71 // 0 0 ...
72 return {0, 2, 1, 2};
73 case 4:
74 // Temporal layer structure:
75 // 3 3 3 3 3 3 3 3 ...
76 // 2 2 2 2 ...
77 // 1 1 ...
78 // 0 0 ...
79 return {0, 3, 2, 3, 1, 3, 2, 3};
80 default:
81 RTC_DCHECK_NOTREACHED();
82 break;
83 }
84 RTC_DCHECK_NOTREACHED();
85 return {0};
86 }
87
GetUpdatedBuffers(const Vp8FrameConfig & config)88 uint8_t GetUpdatedBuffers(const Vp8FrameConfig& config) {
89 uint8_t flags = 0;
90 if (config.last_buffer_flags & BufferFlags::kUpdate) {
91 flags |= static_cast<uint8_t>(Vp8BufferReference::kLast);
92 }
93 if (config.golden_buffer_flags & BufferFlags::kUpdate) {
94 flags |= static_cast<uint8_t>(Vp8BufferReference::kGolden);
95 }
96 if (config.arf_buffer_flags & BufferFlags::kUpdate) {
97 flags |= static_cast<uint8_t>(Vp8BufferReference::kAltref);
98 }
99 return flags;
100 }
101
BufferToIndex(Vp8BufferReference buffer)102 size_t BufferToIndex(Vp8BufferReference buffer) {
103 switch (buffer) {
104 case Vp8FrameConfig::Vp8BufferReference::kLast:
105 return 0;
106 case Vp8FrameConfig::Vp8BufferReference::kGolden:
107 return 1;
108 case Vp8FrameConfig::Vp8BufferReference::kAltref:
109 return 2;
110 case Vp8FrameConfig::Vp8BufferReference::kNone:
111 RTC_CHECK_NOTREACHED();
112 }
113 }
114
115 } // namespace
116
117 constexpr size_t DefaultTemporalLayers::kNumReferenceBuffers;
118
119 std::vector<DefaultTemporalLayers::DependencyInfo>
GetDependencyInfo(size_t num_layers)120 DefaultTemporalLayers::GetDependencyInfo(size_t num_layers) {
121 // For indexing in the patterns described below (which temporal layers they
122 // belong to), see the diagram above.
123 // Layer sync is done similarly for all patterns (except single stream) and
124 // happens every 8 frames:
125 // TL1 layer syncs by periodically by only referencing TL0 ('last'), but still
126 // updating 'golden', so it can be used as a reference by future TL1 frames.
127 // TL2 layer syncs just before TL1 by only depending on TL0 (and not depending
128 // on TL1's buffer before TL1 has layer synced).
129 // TODO(pbos): Consider cyclically updating 'arf' (and 'golden' for 1TL) for
130 // the base layer in 1-3TL instead of 'last' periodically on long intervals,
131 // so that if scene changes occur (user walks between rooms or rotates webcam)
132 // the 'arf' (or 'golden' respectively) is not stuck on a no-longer relevant
133 // keyframe.
134
135 switch (num_layers) {
136 case 1:
137 // Always reference and update the same buffer.
138 return {{"S", {kReferenceAndUpdate, kNone, kNone}}};
139 case 2:
140 // All layers can reference but not update the 'alt' buffer, this means
141 // that the 'alt' buffer reference is effectively the last keyframe.
142 // TL0 also references and updates the 'last' buffer.
143 // TL1 also references 'last' and references and updates 'golden'.
144 if (!field_trial::IsDisabled("WebRTC-UseShortVP8TL2Pattern")) {
145 // Shortened 4-frame pattern:
146 // 1---1 1---1 ...
147 // / / / /
148 // 0---0---0---0 ...
149 return {{"SS", {kReferenceAndUpdate, kNone, kNone}},
150 {"-S", {kReference, kUpdate, kNone}},
151 {"SR", {kReferenceAndUpdate, kNone, kNone}},
152 {"-D", {kReference, kReference, kNone, kFreezeEntropy}}};
153 } else {
154 // "Default" 8-frame pattern:
155 // 1---1---1---1 1---1---1---1 ...
156 // / / / / / / / /
157 // 0---0---0---0---0---0---0---0 ...
158 return {{"SS", {kReferenceAndUpdate, kNone, kNone}},
159 {"-S", {kReference, kUpdate, kNone}},
160 {"SR", {kReferenceAndUpdate, kNone, kNone}},
161 {"-R", {kReference, kReferenceAndUpdate, kNone}},
162 {"SR", {kReferenceAndUpdate, kNone, kNone}},
163 {"-R", {kReference, kReferenceAndUpdate, kNone}},
164 {"SR", {kReferenceAndUpdate, kNone, kNone}},
165 {"-D", {kReference, kReference, kNone, kFreezeEntropy}}};
166 }
167 case 3:
168 if (field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) {
169 // This field trial is intended to check if it is worth using a shorter
170 // temporal pattern, trading some coding efficiency for less risk of
171 // dropped frames.
172 // The coding efficiency will decrease somewhat since the higher layer
173 // state is more volatile, but it will be offset slightly by updating
174 // the altref buffer with TL2 frames, instead of just referencing lower
175 // layers.
176 // If a frame is dropped in a higher layer, the jitter
177 // buffer on the receive side won't be able to decode any higher layer
178 // frame until the next sync frame. So we expect a noticeable decrease
179 // in frame drops on links with high packet loss.
180
181 // TL0 references and updates the 'last' buffer.
182 // TL1 references 'last' and references and updates 'golden'.
183 // TL2 references both 'last' & 'golden' and references and updates
184 // 'arf'.
185 // 2-------2 2-------2 2
186 // / __/ / __/ /
187 // / __1 / __1 /
188 // /___/ /___/ /
189 // 0---------------0---------------0-----
190 // 0 1 2 3 4 5 6 7 8 9 ...
191 return {{"SSS", {kReferenceAndUpdate, kNone, kNone}},
192 {"--S", {kReference, kNone, kUpdate}},
193 {"-DR", {kReference, kUpdate, kNone}},
194 {"--D", {kReference, kReference, kReference, kFreezeEntropy}}};
195 } else {
196 // All layers can reference but not update the 'alt' buffer, this means
197 // that the 'alt' buffer reference is effectively the last keyframe.
198 // TL0 also references and updates the 'last' buffer.
199 // TL1 also references 'last' and references and updates 'golden'.
200 // TL2 references both 'last' and 'golden' but updates no buffer.
201 // 2 __2 _____2 __2 2
202 // / /____/ / / /
203 // / 1---------/-----1 /
204 // /_____/ /_____/ /
205 // 0---------------0---------------0-----
206 // 0 1 2 3 4 5 6 7 8 9 ...
207 return {{"SSS", {kReferenceAndUpdate, kNone, kNone}},
208 {"--D", {kReference, kNone, kNone, kFreezeEntropy}},
209 {"-SS", {kReference, kUpdate, kNone}},
210 {"--D", {kReference, kReference, kNone, kFreezeEntropy}},
211 {"SRR", {kReferenceAndUpdate, kNone, kNone}},
212 {"--D", {kReference, kReference, kNone, kFreezeEntropy}},
213 {"-DS", {kReference, kReferenceAndUpdate, kNone}},
214 {"--D", {kReference, kReference, kNone, kFreezeEntropy}}};
215 }
216 case 4:
217 // TL0 references and updates only the 'last' buffer.
218 // TL1 references 'last' and updates and references 'golden'.
219 // TL2 references 'last' and 'golden', and references and updates 'arf'.
220 // TL3 references all buffers but update none of them.
221 // TODO(philipel): Set decode target information for this structure.
222 return {{"----", {kReferenceAndUpdate, kNone, kNone}},
223 {"----", {kReference, kNone, kNone, kFreezeEntropy}},
224 {"----", {kReference, kNone, kUpdate}},
225 {"----", {kReference, kNone, kReference, kFreezeEntropy}},
226 {"----", {kReference, kUpdate, kNone}},
227 {"----", {kReference, kReference, kReference, kFreezeEntropy}},
228 {"----", {kReference, kReference, kReferenceAndUpdate}},
229 {"----", {kReference, kReference, kReference, kFreezeEntropy}},
230 {"----", {kReferenceAndUpdate, kNone, kNone}},
231 {"----", {kReference, kReference, kReference, kFreezeEntropy}},
232 {"----", {kReference, kReference, kReferenceAndUpdate}},
233 {"----", {kReference, kReference, kReference, kFreezeEntropy}},
234 {"----", {kReference, kReferenceAndUpdate, kNone}},
235 {"----", {kReference, kReference, kReference, kFreezeEntropy}},
236 {"----", {kReference, kReference, kReferenceAndUpdate}},
237 {"----", {kReference, kReference, kReference, kFreezeEntropy}}};
238 default:
239 RTC_DCHECK_NOTREACHED();
240 break;
241 }
242 RTC_DCHECK_NOTREACHED();
243 return {{"", {kNone, kNone, kNone}}};
244 }
245
246 std::bitset<DefaultTemporalLayers::kNumReferenceBuffers>
DetermineStaticBuffers(const std::vector<DependencyInfo> & temporal_pattern)247 DefaultTemporalLayers::DetermineStaticBuffers(
248 const std::vector<DependencyInfo>& temporal_pattern) {
249 std::bitset<kNumReferenceBuffers> buffers;
250 buffers.set();
251 for (const DependencyInfo& info : temporal_pattern) {
252 uint8_t updated_buffers = GetUpdatedBuffers(info.frame_config);
253
254 for (Vp8BufferReference buffer : kAllBuffers) {
255 if (static_cast<uint8_t>(buffer) & updated_buffers) {
256 buffers.reset(BufferToIndex(buffer));
257 }
258 }
259 }
260 return buffers;
261 }
262
DefaultTemporalLayers(int number_of_temporal_layers)263 DefaultTemporalLayers::DefaultTemporalLayers(int number_of_temporal_layers)
264 : num_layers_(std::max(1, number_of_temporal_layers)),
265 temporal_ids_(GetTemporalIds(num_layers_)),
266 temporal_pattern_(GetDependencyInfo(num_layers_)),
267 is_static_buffer_(DetermineStaticBuffers(temporal_pattern_)),
268 pattern_idx_(kUninitializedPatternIndex),
269 new_bitrates_bps_(std::vector<uint32_t>(num_layers_, 0u)) {
270 RTC_CHECK_GE(kMaxTemporalStreams, number_of_temporal_layers);
271 RTC_CHECK_GE(number_of_temporal_layers, 0);
272 RTC_CHECK_LE(number_of_temporal_layers, 4);
273 // pattern_idx_ wraps around temporal_pattern_.size, this is incorrect if
274 // temporal_ids_ are ever longer. If this is no longer correct it needs to
275 // wrap at max(temporal_ids_.size(), temporal_pattern_.size()).
276 RTC_DCHECK_LE(temporal_ids_.size(), temporal_pattern_.size());
277
278 RTC_DCHECK(
279 checker_ = TemporalLayersChecker::CreateTemporalLayersChecker(
280 Vp8TemporalLayersType::kFixedPattern, number_of_temporal_layers));
281
282 // Always need to start with a keyframe, so pre-populate all frame counters.
283 frames_since_buffer_refresh_.fill(0);
284 }
285
286 DefaultTemporalLayers::~DefaultTemporalLayers() = default;
287
SetQpLimits(size_t stream_index,int min_qp,int max_qp)288 void DefaultTemporalLayers::SetQpLimits(size_t stream_index,
289 int min_qp,
290 int max_qp) {
291 RTC_DCHECK_LT(stream_index, StreamCount());
292 // Ignore.
293 }
294
StreamCount() const295 size_t DefaultTemporalLayers::StreamCount() const {
296 return 1;
297 }
298
SupportsEncoderFrameDropping(size_t stream_index) const299 bool DefaultTemporalLayers::SupportsEncoderFrameDropping(
300 size_t stream_index) const {
301 RTC_DCHECK_LT(stream_index, StreamCount());
302 // This class allows the encoder drop frames as it sees fit.
303 return true;
304 }
305
OnRatesUpdated(size_t stream_index,const std::vector<uint32_t> & bitrates_bps,int framerate_fps)306 void DefaultTemporalLayers::OnRatesUpdated(
307 size_t stream_index,
308 const std::vector<uint32_t>& bitrates_bps,
309 int framerate_fps) {
310 RTC_DCHECK_LT(stream_index, StreamCount());
311 RTC_DCHECK_GT(bitrates_bps.size(), 0);
312 RTC_DCHECK_LE(bitrates_bps.size(), num_layers_);
313 // `bitrates_bps` uses individual rate per layer, but Vp8EncoderConfig wants
314 // the accumulated rate, so sum them up.
315 new_bitrates_bps_ = bitrates_bps;
316 new_bitrates_bps_->resize(num_layers_);
317 for (size_t i = 1; i < num_layers_; ++i) {
318 (*new_bitrates_bps_)[i] += (*new_bitrates_bps_)[i - 1];
319 }
320 }
321
UpdateConfiguration(size_t stream_index)322 Vp8EncoderConfig DefaultTemporalLayers::UpdateConfiguration(
323 size_t stream_index) {
324 RTC_DCHECK_LT(stream_index, StreamCount());
325
326 Vp8EncoderConfig config;
327
328 if (!new_bitrates_bps_) {
329 return config;
330 }
331
332 config.temporal_layer_config.emplace();
333 Vp8EncoderConfig::TemporalLayerConfig& ts_config =
334 config.temporal_layer_config.value();
335
336 for (size_t i = 0; i < num_layers_; ++i) {
337 ts_config.ts_target_bitrate[i] = (*new_bitrates_bps_)[i] / 1000;
338 // ..., 4, 2, 1
339 ts_config.ts_rate_decimator[i] = 1 << (num_layers_ - i - 1);
340 }
341
342 ts_config.ts_number_layers = num_layers_;
343 ts_config.ts_periodicity = temporal_ids_.size();
344 std::copy(temporal_ids_.begin(), temporal_ids_.end(),
345 ts_config.ts_layer_id.begin());
346
347 new_bitrates_bps_.reset();
348
349 return config;
350 }
351
IsSyncFrame(const Vp8FrameConfig & config) const352 bool DefaultTemporalLayers::IsSyncFrame(const Vp8FrameConfig& config) const {
353 // Since we always assign TL0 to 'last' in these patterns, we can infer layer
354 // sync by checking if temporal id > 0 and we only reference TL0 or buffers
355 // containing the last key-frame.
356 if (config.packetizer_temporal_idx == 0) {
357 // TL0 frames are per definition not sync frames.
358 return false;
359 }
360
361 if ((config.last_buffer_flags & BufferFlags::kReference) == 0) {
362 // Sync frames must reference TL0.
363 return false;
364 }
365
366 if ((config.golden_buffer_flags & BufferFlags::kReference) &&
367 !is_static_buffer_[BufferToIndex(Vp8BufferReference::kGolden)]) {
368 // Referencing a golden frame that contains a non-(base layer|key frame).
369 return false;
370 }
371 if ((config.arf_buffer_flags & BufferFlags::kReference) &&
372 !is_static_buffer_[BufferToIndex(Vp8BufferReference::kAltref)]) {
373 // Referencing an altref frame that contains a non-(base layer|key frame).
374 return false;
375 }
376
377 return true;
378 }
379
NextFrameConfig(size_t stream_index,uint32_t timestamp)380 Vp8FrameConfig DefaultTemporalLayers::NextFrameConfig(size_t stream_index,
381 uint32_t timestamp) {
382 RTC_DCHECK_LT(stream_index, StreamCount());
383 RTC_DCHECK_GT(num_layers_, 0);
384 RTC_DCHECK_GT(temporal_pattern_.size(), 0);
385
386 RTC_DCHECK_GT(kUninitializedPatternIndex, temporal_pattern_.size());
387 const bool first_frame = (pattern_idx_ == kUninitializedPatternIndex);
388
389 pattern_idx_ = (pattern_idx_ + 1) % temporal_pattern_.size();
390 DependencyInfo dependency_info = temporal_pattern_[pattern_idx_];
391 Vp8FrameConfig& tl_config = dependency_info.frame_config;
392 tl_config.encoder_layer_id = tl_config.packetizer_temporal_idx =
393 temporal_ids_[pattern_idx_ % temporal_ids_.size()];
394
395 if (pattern_idx_ == 0) {
396 // Start of new pattern iteration, set up clear state by invalidating any
397 // pending frames, so that we don't make an invalid reference to a buffer
398 // containing data from a previous iteration.
399 for (auto& frame : pending_frames_) {
400 frame.expired = true;
401 }
402 }
403
404 if (first_frame) {
405 tl_config = Vp8FrameConfig::GetIntraFrameConfig();
406 } else {
407 // Last is always ok to reference as it contains the base layer. For other
408 // buffers though, we need to check if the buffer has actually been
409 // refreshed this cycle of the temporal pattern. If the encoder dropped
410 // a frame, it might not have.
411 ValidateReferences(&tl_config.golden_buffer_flags,
412 Vp8BufferReference::kGolden);
413 ValidateReferences(&tl_config.arf_buffer_flags,
414 Vp8BufferReference::kAltref);
415 // Update search order to let the encoder know which buffers contains the
416 // most recent data.
417 UpdateSearchOrder(&tl_config);
418 // Figure out if this a sync frame (non-base-layer frame with only
419 // base-layer references).
420 tl_config.layer_sync = IsSyncFrame(tl_config);
421
422 // Increment frame age, this needs to be in sync with `pattern_idx_`,
423 // so must update it here. Resetting age to 0 must be done when encoding is
424 // complete though, and so in the case of pipelining encoder it might lag.
425 // To prevent this data spill over into the next iteration,
426 // the `pedning_frames_` map is reset in loops. If delay is constant,
427 // the relative age should still be OK for the search order.
428 for (size_t& n : frames_since_buffer_refresh_) {
429 ++n;
430 }
431 }
432
433 // Add frame to set of pending frames, awaiting completion.
434 pending_frames_.emplace_back(timestamp, false, GetUpdatedBuffers(tl_config),
435 dependency_info);
436
437 // Checker does not yet support encoder frame dropping, so validate flags
438 // here before they can be dropped.
439 // TODO(sprang): Update checker to support dropping.
440 RTC_DCHECK(checker_->CheckTemporalConfig(first_frame, tl_config));
441
442 return tl_config;
443 }
444
ValidateReferences(BufferFlags * flags,Vp8BufferReference ref) const445 void DefaultTemporalLayers::ValidateReferences(BufferFlags* flags,
446 Vp8BufferReference ref) const {
447 // Check if the buffer specified by `ref` is actually referenced, and if so
448 // if it also a dynamically updating one (buffers always just containing
449 // keyframes are always safe to reference).
450 if ((*flags & BufferFlags::kReference) &&
451 !is_static_buffer_[BufferToIndex(ref)]) {
452 if (NumFramesSinceBufferRefresh(ref) >= pattern_idx_) {
453 // No valid buffer state, or buffer contains frame that is older than the
454 // current pattern. This reference is not valid, so remove it.
455 *flags = static_cast<BufferFlags>(*flags & ~BufferFlags::kReference);
456 }
457 }
458 }
459
UpdateSearchOrder(Vp8FrameConfig * config)460 void DefaultTemporalLayers::UpdateSearchOrder(Vp8FrameConfig* config) {
461 // Figure out which of the buffers we can reference, and order them so that
462 // the most recently refreshed is first. Otherwise prioritize last first,
463 // golden second, and altref third.
464 using BufferRefAge = std::pair<Vp8BufferReference, size_t>;
465 std::vector<BufferRefAge> eligible_buffers;
466 if (config->last_buffer_flags & BufferFlags::kReference) {
467 eligible_buffers.emplace_back(
468 Vp8BufferReference::kLast,
469 NumFramesSinceBufferRefresh(Vp8BufferReference::kLast));
470 }
471 if (config->golden_buffer_flags & BufferFlags::kReference) {
472 eligible_buffers.emplace_back(
473 Vp8BufferReference::kGolden,
474 NumFramesSinceBufferRefresh(Vp8BufferReference::kGolden));
475 }
476 if (config->arf_buffer_flags & BufferFlags::kReference) {
477 eligible_buffers.emplace_back(
478 Vp8BufferReference::kAltref,
479 NumFramesSinceBufferRefresh(Vp8BufferReference::kAltref));
480 }
481
482 std::sort(eligible_buffers.begin(), eligible_buffers.end(),
483 [](const BufferRefAge& lhs, const BufferRefAge& rhs) {
484 if (lhs.second != rhs.second) {
485 // Lower count has highest precedence.
486 return lhs.second < rhs.second;
487 }
488 return lhs.first < rhs.first;
489 });
490
491 // Populate the search order fields where possible.
492 if (!eligible_buffers.empty()) {
493 config->first_reference = eligible_buffers.front().first;
494 if (eligible_buffers.size() > 1)
495 config->second_reference = eligible_buffers[1].first;
496 }
497 }
498
NumFramesSinceBufferRefresh(Vp8FrameConfig::Vp8BufferReference ref) const499 size_t DefaultTemporalLayers::NumFramesSinceBufferRefresh(
500 Vp8FrameConfig::Vp8BufferReference ref) const {
501 return frames_since_buffer_refresh_[BufferToIndex(ref)];
502 }
503
ResetNumFramesSinceBufferRefresh(Vp8FrameConfig::Vp8BufferReference ref)504 void DefaultTemporalLayers::ResetNumFramesSinceBufferRefresh(
505 Vp8FrameConfig::Vp8BufferReference ref) {
506 frames_since_buffer_refresh_[BufferToIndex(ref)] = 0;
507 }
508
CullPendingFramesBefore(uint32_t timestamp)509 void DefaultTemporalLayers::CullPendingFramesBefore(uint32_t timestamp) {
510 while (!pending_frames_.empty() &&
511 pending_frames_.front().timestamp != timestamp) {
512 pending_frames_.pop_front();
513 }
514 }
515
OnEncodeDone(size_t stream_index,uint32_t rtp_timestamp,size_t size_bytes,bool is_keyframe,int qp,CodecSpecificInfo * info)516 void DefaultTemporalLayers::OnEncodeDone(size_t stream_index,
517 uint32_t rtp_timestamp,
518 size_t size_bytes,
519 bool is_keyframe,
520 int qp,
521 CodecSpecificInfo* info) {
522 RTC_DCHECK_LT(stream_index, StreamCount());
523 RTC_DCHECK_GT(num_layers_, 0);
524
525 if (size_bytes == 0) {
526 RTC_LOG(LS_WARNING) << "Empty frame; treating as dropped.";
527 OnFrameDropped(stream_index, rtp_timestamp);
528 return;
529 }
530
531 CullPendingFramesBefore(rtp_timestamp);
532 RTC_CHECK(!pending_frames_.empty());
533 PendingFrame& frame = pending_frames_.front();
534 RTC_DCHECK_EQ(frame.timestamp, rtp_timestamp);
535 const Vp8FrameConfig& frame_config = frame.dependency_info.frame_config;
536 if (is_keyframe) {
537 // Signal key-frame so checker resets state.
538 RTC_DCHECK(checker_->CheckTemporalConfig(true, frame_config));
539 }
540
541 CodecSpecificInfoVP8& vp8_info = info->codecSpecific.VP8;
542 if (num_layers_ == 1) {
543 vp8_info.temporalIdx = kNoTemporalIdx;
544 vp8_info.layerSync = false;
545 } else {
546 if (is_keyframe) {
547 // Restart the temporal pattern on keyframes.
548 pattern_idx_ = 0;
549 vp8_info.temporalIdx = 0;
550 vp8_info.layerSync = true; // Keyframes are always sync frames.
551
552 for (Vp8BufferReference buffer : kAllBuffers) {
553 if (is_static_buffer_[BufferToIndex(buffer)]) {
554 // Update frame count of all kf-only buffers, regardless of state of
555 // `pending_frames_`.
556 ResetNumFramesSinceBufferRefresh(buffer);
557 } else {
558 // Key-frames update all buffers, this should be reflected when
559 // updating state in FrameEncoded().
560 frame.updated_buffer_mask |= static_cast<uint8_t>(buffer);
561 }
562 }
563 } else {
564 // Delta frame, update codec specifics with temporal id and sync flag.
565 vp8_info.temporalIdx = frame_config.packetizer_temporal_idx;
566 vp8_info.layerSync = frame_config.layer_sync;
567 }
568 }
569
570 vp8_info.useExplicitDependencies = true;
571 RTC_DCHECK_EQ(vp8_info.referencedBuffersCount, 0u);
572 RTC_DCHECK_EQ(vp8_info.updatedBuffersCount, 0u);
573
574 GenericFrameInfo& generic_frame_info = info->generic_frame_info.emplace();
575
576 for (int i = 0; i < static_cast<int>(Vp8FrameConfig::Buffer::kCount); ++i) {
577 bool references = false;
578 bool updates = is_keyframe;
579
580 if (!is_keyframe &&
581 frame_config.References(static_cast<Vp8FrameConfig::Buffer>(i))) {
582 RTC_DCHECK_LT(vp8_info.referencedBuffersCount,
583 arraysize(CodecSpecificInfoVP8::referencedBuffers));
584 references = true;
585 vp8_info.referencedBuffers[vp8_info.referencedBuffersCount++] = i;
586 }
587
588 if (is_keyframe ||
589 frame_config.Updates(static_cast<Vp8FrameConfig::Buffer>(i))) {
590 RTC_DCHECK_LT(vp8_info.updatedBuffersCount,
591 arraysize(CodecSpecificInfoVP8::updatedBuffers));
592 updates = true;
593 vp8_info.updatedBuffers[vp8_info.updatedBuffersCount++] = i;
594 }
595
596 if (references || updates) {
597 generic_frame_info.encoder_buffers.emplace_back(i, references, updates);
598 }
599 }
600
601 // The templates are always present on keyframes, and then refered to by
602 // subsequent frames.
603 if (is_keyframe) {
604 info->template_structure = GetTemplateStructure(num_layers_);
605 generic_frame_info.decode_target_indications =
606 temporal_pattern_.front().decode_target_indications;
607 generic_frame_info.temporal_id = 0;
608 } else {
609 generic_frame_info.decode_target_indications =
610 frame.dependency_info.decode_target_indications;
611 generic_frame_info.temporal_id = frame_config.packetizer_temporal_idx;
612 }
613
614 if (!frame.expired) {
615 for (Vp8BufferReference buffer : kAllBuffers) {
616 if (frame.updated_buffer_mask & static_cast<uint8_t>(buffer)) {
617 ResetNumFramesSinceBufferRefresh(buffer);
618 }
619 }
620 }
621
622 pending_frames_.pop_front();
623 }
624
OnFrameDropped(size_t stream_index,uint32_t rtp_timestamp)625 void DefaultTemporalLayers::OnFrameDropped(size_t stream_index,
626 uint32_t rtp_timestamp) {
627 CullPendingFramesBefore(rtp_timestamp);
628 RTC_CHECK(!pending_frames_.empty());
629 RTC_DCHECK_EQ(pending_frames_.front().timestamp, rtp_timestamp);
630 pending_frames_.pop_front();
631 }
632
OnPacketLossRateUpdate(float packet_loss_rate)633 void DefaultTemporalLayers::OnPacketLossRateUpdate(float packet_loss_rate) {}
634
OnRttUpdate(int64_t rtt_ms)635 void DefaultTemporalLayers::OnRttUpdate(int64_t rtt_ms) {}
636
OnLossNotification(const VideoEncoder::LossNotification & loss_notification)637 void DefaultTemporalLayers::OnLossNotification(
638 const VideoEncoder::LossNotification& loss_notification) {}
639
GetTemplateStructure(int num_layers) const640 FrameDependencyStructure DefaultTemporalLayers::GetTemplateStructure(
641 int num_layers) const {
642 RTC_CHECK_LT(num_layers, 5);
643 RTC_CHECK_GT(num_layers, 0);
644
645 FrameDependencyStructure template_structure;
646 template_structure.num_decode_targets = num_layers;
647
648 switch (num_layers) {
649 case 1: {
650 template_structure.templates.resize(2);
651 template_structure.templates[0].T(0).Dtis("S");
652 template_structure.templates[1].T(0).Dtis("S").FrameDiffs({1});
653 return template_structure;
654 }
655 case 2: {
656 template_structure.templates.resize(5);
657 template_structure.templates[0].T(0).Dtis("SS");
658 template_structure.templates[1].T(0).Dtis("SS").FrameDiffs({2});
659 template_structure.templates[2].T(0).Dtis("SR").FrameDiffs({2});
660 template_structure.templates[3].T(1).Dtis("-S").FrameDiffs({1});
661 template_structure.templates[4].T(1).Dtis("-D").FrameDiffs({2, 1});
662 return template_structure;
663 }
664 case 3: {
665 if (field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) {
666 template_structure.templates.resize(5);
667 template_structure.templates[0].T(0).Dtis("SSS");
668 template_structure.templates[1].T(0).Dtis("SSS").FrameDiffs({4});
669 template_structure.templates[2].T(1).Dtis("-DR").FrameDiffs({2});
670 template_structure.templates[3].T(2).Dtis("--S").FrameDiffs({1});
671 template_structure.templates[4].T(2).Dtis("--D").FrameDiffs({2, 1});
672 } else {
673 template_structure.templates.resize(7);
674 template_structure.templates[0].T(0).Dtis("SSS");
675 template_structure.templates[1].T(0).Dtis("SSS").FrameDiffs({4});
676 template_structure.templates[2].T(0).Dtis("SRR").FrameDiffs({4});
677 template_structure.templates[3].T(1).Dtis("-SS").FrameDiffs({2});
678 template_structure.templates[4].T(1).Dtis("-DS").FrameDiffs({4, 2});
679 template_structure.templates[5].T(2).Dtis("--D").FrameDiffs({1});
680 template_structure.templates[6].T(2).Dtis("--D").FrameDiffs({3, 1});
681 }
682 return template_structure;
683 }
684 case 4: {
685 template_structure.templates.resize(8);
686 template_structure.templates[0].T(0).Dtis("SSSS");
687 template_structure.templates[1].T(0).Dtis("SSSS").FrameDiffs({8});
688 template_structure.templates[2].T(1).Dtis("-SRR").FrameDiffs({4});
689 template_structure.templates[3].T(1).Dtis("-SRR").FrameDiffs({4, 8});
690 template_structure.templates[4].T(2).Dtis("--SR").FrameDiffs({2});
691 template_structure.templates[5].T(2).Dtis("--SR").FrameDiffs({2, 4});
692 template_structure.templates[6].T(3).Dtis("---D").FrameDiffs({1});
693 template_structure.templates[7].T(3).Dtis("---D").FrameDiffs({1, 3});
694 return template_structure;
695 }
696 default:
697 RTC_DCHECK_NOTREACHED();
698 // To make the compiler happy!
699 return template_structure;
700 }
701 }
702
703 // Returns list of temporal dependencies for each frame in the temporal pattern.
704 // Values are lists of indecies in the pattern.
GetTemporalDependencies(int num_temporal_layers)705 std::vector<std::set<uint8_t>> GetTemporalDependencies(
706 int num_temporal_layers) {
707 switch (num_temporal_layers) {
708 case 1:
709 return {{0}};
710 case 2:
711 if (!field_trial::IsDisabled("WebRTC-UseShortVP8TL2Pattern")) {
712 return {{2}, {0}, {0}, {1, 2}};
713 } else {
714 return {{6}, {0}, {0}, {1, 2}, {2}, {3, 4}, {4}, {5, 6}};
715 }
716 case 3:
717 if (field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) {
718 return {{0}, {0}, {0}, {0, 1, 2}};
719 } else {
720 return {{4}, {0}, {0}, {0, 2}, {0}, {2, 4}, {2, 4}, {4, 6}};
721 }
722 case 4:
723 return {{8}, {0}, {0}, {0, 2},
724 {0}, {0, 2, 4}, {0, 2, 4}, {0, 4, 6},
725 {0}, {4, 6, 8}, {4, 6, 8}, {4, 8, 10},
726 {4, 8}, {8, 10, 12}, {8, 10, 12}, {8, 12, 14}};
727 default:
728 RTC_DCHECK_NOTREACHED();
729 return {};
730 }
731 }
732
DefaultTemporalLayersChecker(int num_temporal_layers)733 DefaultTemporalLayersChecker::DefaultTemporalLayersChecker(
734 int num_temporal_layers)
735 : TemporalLayersChecker(num_temporal_layers),
736 num_layers_(std::max(1, num_temporal_layers)),
737 temporal_ids_(GetTemporalIds(num_layers_)),
738 temporal_dependencies_(GetTemporalDependencies(num_layers_)),
739 pattern_idx_(255) {
740 int i = 0;
741 while (temporal_ids_.size() < temporal_dependencies_.size()) {
742 temporal_ids_.push_back(temporal_ids_[i++]);
743 }
744 }
745
746 DefaultTemporalLayersChecker::~DefaultTemporalLayersChecker() = default;
747
CheckTemporalConfig(bool frame_is_keyframe,const Vp8FrameConfig & frame_config)748 bool DefaultTemporalLayersChecker::CheckTemporalConfig(
749 bool frame_is_keyframe,
750 const Vp8FrameConfig& frame_config) {
751 if (!TemporalLayersChecker::CheckTemporalConfig(frame_is_keyframe,
752 frame_config)) {
753 return false;
754 }
755 if (frame_config.drop_frame) {
756 return true;
757 }
758
759 if (frame_is_keyframe) {
760 pattern_idx_ = 0;
761 last_ = BufferState();
762 golden_ = BufferState();
763 arf_ = BufferState();
764 return true;
765 }
766
767 ++pattern_idx_;
768 if (pattern_idx_ == temporal_ids_.size()) {
769 // All non key-frame buffers should be updated each pattern cycle.
770 if (!last_.is_keyframe && !last_.is_updated_this_cycle) {
771 RTC_LOG(LS_ERROR) << "Last buffer was not updated during pattern cycle.";
772 return false;
773 }
774 if (!arf_.is_keyframe && !arf_.is_updated_this_cycle) {
775 RTC_LOG(LS_ERROR) << "Arf buffer was not updated during pattern cycle.";
776 return false;
777 }
778 if (!golden_.is_keyframe && !golden_.is_updated_this_cycle) {
779 RTC_LOG(LS_ERROR)
780 << "Golden buffer was not updated during pattern cycle.";
781 return false;
782 }
783 last_.is_updated_this_cycle = false;
784 arf_.is_updated_this_cycle = false;
785 golden_.is_updated_this_cycle = false;
786 pattern_idx_ = 0;
787 }
788 uint8_t expected_tl_idx = temporal_ids_[pattern_idx_];
789 if (frame_config.packetizer_temporal_idx != expected_tl_idx) {
790 RTC_LOG(LS_ERROR) << "Frame has an incorrect temporal index. Expected: "
791 << static_cast<int>(expected_tl_idx) << " Actual: "
792 << static_cast<int>(frame_config.packetizer_temporal_idx);
793 return false;
794 }
795
796 bool need_sync = temporal_ids_[pattern_idx_] > 0 &&
797 temporal_ids_[pattern_idx_] != kNoTemporalIdx;
798 std::vector<int> dependencies;
799
800 if (frame_config.last_buffer_flags & BufferFlags::kReference) {
801 uint8_t referenced_layer = temporal_ids_[last_.pattern_idx];
802 if (referenced_layer > 0) {
803 need_sync = false;
804 }
805 if (!last_.is_keyframe) {
806 dependencies.push_back(last_.pattern_idx);
807 }
808 } else if (frame_config.first_reference == Vp8BufferReference::kLast ||
809 frame_config.second_reference == Vp8BufferReference::kLast) {
810 RTC_LOG(LS_ERROR)
811 << "Last buffer not referenced, but present in search order.";
812 return false;
813 }
814
815 if (frame_config.arf_buffer_flags & BufferFlags::kReference) {
816 uint8_t referenced_layer = temporal_ids_[arf_.pattern_idx];
817 if (referenced_layer > 0) {
818 need_sync = false;
819 }
820 if (!arf_.is_keyframe) {
821 dependencies.push_back(arf_.pattern_idx);
822 }
823 } else if (frame_config.first_reference == Vp8BufferReference::kAltref ||
824 frame_config.second_reference == Vp8BufferReference::kAltref) {
825 RTC_LOG(LS_ERROR)
826 << "Altret buffer not referenced, but present in search order.";
827 return false;
828 }
829
830 if (frame_config.golden_buffer_flags & BufferFlags::kReference) {
831 uint8_t referenced_layer = temporal_ids_[golden_.pattern_idx];
832 if (referenced_layer > 0) {
833 need_sync = false;
834 }
835 if (!golden_.is_keyframe) {
836 dependencies.push_back(golden_.pattern_idx);
837 }
838 } else if (frame_config.first_reference == Vp8BufferReference::kGolden ||
839 frame_config.second_reference == Vp8BufferReference::kGolden) {
840 RTC_LOG(LS_ERROR)
841 << "Golden buffer not referenced, but present in search order.";
842 return false;
843 }
844
845 if (need_sync != frame_config.layer_sync) {
846 RTC_LOG(LS_ERROR) << "Sync bit is set incorrectly on a frame. Expected: "
847 << need_sync << " Actual: " << frame_config.layer_sync;
848 return false;
849 }
850
851 if (!frame_is_keyframe) {
852 size_t i;
853 for (i = 0; i < dependencies.size(); ++i) {
854 if (temporal_dependencies_[pattern_idx_].find(dependencies[i]) ==
855 temporal_dependencies_[pattern_idx_].end()) {
856 RTC_LOG(LS_ERROR)
857 << "Illegal temporal dependency out of defined pattern "
858 "from position "
859 << static_cast<int>(pattern_idx_) << " to position "
860 << static_cast<int>(dependencies[i]);
861 return false;
862 }
863 }
864 }
865
866 if (frame_config.last_buffer_flags & BufferFlags::kUpdate) {
867 last_.is_updated_this_cycle = true;
868 last_.pattern_idx = pattern_idx_;
869 last_.is_keyframe = false;
870 }
871 if (frame_config.arf_buffer_flags & BufferFlags::kUpdate) {
872 arf_.is_updated_this_cycle = true;
873 arf_.pattern_idx = pattern_idx_;
874 arf_.is_keyframe = false;
875 }
876 if (frame_config.golden_buffer_flags & BufferFlags::kUpdate) {
877 golden_.is_updated_this_cycle = true;
878 golden_.pattern_idx = pattern_idx_;
879 golden_.is_keyframe = false;
880 }
881 return true;
882 }
883
884 } // namespace webrtc
885