/* * 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/codecs/av1/scalability_structure_l1t2.h" #include #include #include "absl/base/macros.h" #include "api/transport/rtp/dependency_descriptor.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace { constexpr auto kNotPresent = DecodeTargetIndication::kNotPresent; constexpr auto kDiscardable = DecodeTargetIndication::kDiscardable; constexpr auto kSwitch = DecodeTargetIndication::kSwitch; constexpr DecodeTargetIndication kDtis[3][2] = { {kSwitch, kSwitch}, // KeyFrame {kNotPresent, kDiscardable}, // DeltaFrame T1 {kSwitch, kSwitch}, // DeltaFrame T0 }; } // namespace ScalabilityStructureL1T2::~ScalabilityStructureL1T2() = default; ScalableVideoController::StreamLayersConfig ScalabilityStructureL1T2::StreamConfig() const { StreamLayersConfig result; result.num_spatial_layers = 1; result.num_temporal_layers = 2; return result; } FrameDependencyStructure ScalabilityStructureL1T2::DependencyStructure() const { FrameDependencyStructure structure; structure.num_decode_targets = 2; structure.num_chains = 1; structure.decode_target_protected_by_chain = {0, 0}; structure.templates.resize(3); structure.templates[0].T(0).Dtis("SS").ChainDiffs({0}); structure.templates[1].T(0).Dtis("SS").ChainDiffs({2}).FrameDiffs({2}); structure.templates[2].T(1).Dtis("-D").ChainDiffs({1}).FrameDiffs({1}); return structure; } std::vector ScalabilityStructureL1T2::NextFrameConfig(bool restart) { if (!active_decode_targets_[0]) { RTC_LOG(LS_WARNING) << "No bitrate allocated for temporal layer 0, yet " "frame is requested. No frame will be encoded."; return {}; } if (restart) { next_pattern_ = kKeyFrame; } else if (!active_decode_targets_[1]) { next_pattern_ = kDeltaFrameT0; } std::vector result(1); switch (next_pattern_) { case kKeyFrame: result[0].Id(0).T(0).Keyframe().Update(0); next_pattern_ = kDeltaFrameT1; break; case kDeltaFrameT1: result[0].Id(1).T(1).Reference(0); next_pattern_ = kDeltaFrameT0; break; case kDeltaFrameT0: result[0].Id(2).T(0).ReferenceAndUpdate(0); next_pattern_ = kDeltaFrameT1; break; } return result; } absl::optional ScalabilityStructureL1T2::OnEncodeDone( LayerFrameConfig config) { // Encoder may have generated a keyframe even when not asked for it. Treat // such frame same as requested keyframe, in particular restart the sequence. if (config.IsKeyframe()) { config = NextFrameConfig(/*restart=*/true).front(); } absl::optional frame_info; if (config.Id() < 0 || config.Id() >= int{ABSL_ARRAYSIZE(kDtis)}) { RTC_LOG(LS_ERROR) << "Unexpected config id " << config.Id(); return frame_info; } frame_info.emplace(); frame_info->temporal_id = config.TemporalId(); frame_info->encoder_buffers = config.Buffers(); frame_info->decode_target_indications.assign(std::begin(kDtis[config.Id()]), std::end(kDtis[config.Id()])); frame_info->part_of_chain = {config.TemporalId() == 0}; frame_info->active_decode_targets = active_decode_targets_; return frame_info; } void ScalabilityStructureL1T2::OnRatesUpdated( const VideoBitrateAllocation& bitrates) { if (bitrates.GetBitrate(0, 0) == 0) { // It is unclear what frame can be produced when base layer is disabled, // so mark all decode targets as inactive to produce no frames. active_decode_targets_.reset(); return; } active_decode_targets_.set(0, true); active_decode_targets_.set(1, bitrates.GetBitrate(0, 1) > 0); } } // namespace webrtc