diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn index 301dc7b5c7..b06fc9e8bf 100644 --- a/modules/video_coding/codecs/av1/BUILD.gn +++ b/modules/video_coding/codecs/av1/BUILD.gn @@ -51,6 +51,22 @@ rtc_source_set("scalable_video_controller") { ] } +rtc_source_set("scalability_structures") { + sources = [ + "scalability_structure_l1t2.cc", + "scalability_structure_l1t2.h", + ] + deps = [ + ":scalable_video_controller", + "../../../../api/transport/rtp:dependency_descriptor", + "../../../../common_video/generic_frame_descriptor", + "../../../../rtc_base:checks", + "../../../../rtc_base:logging", + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + rtc_library("libaom_av1_encoder") { visibility = [ "*" ] poisonous = [ "software_video_codecs" ] @@ -73,6 +89,7 @@ rtc_library("libaom_av1_encoder") { "../../../../rtc_base:checks", "../../../../rtc_base:logging", "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/libaom", ] } else { @@ -92,6 +109,7 @@ if (rtc_include_tests) { deps = [ ":libaom_av1_decoder", ":libaom_av1_encoder", + ":scalability_structures", ":scalable_video_controller", "../..:video_codec_interface", "../../../../api:create_frame_generator", diff --git a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc index dfda625a35..a2752e6377 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc @@ -21,6 +21,7 @@ #include "api/video_codecs/video_encoder.h" #include "modules/video_coding/codecs/av1/libaom_av1_decoder.h" #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h" #include "modules/video_coding/codecs/av1/scalable_video_controller.h" #include "modules/video_coding/codecs/av1/scalable_video_controller_no_layering.h" #include "modules/video_coding/include/video_codec_interface.h" @@ -98,6 +99,7 @@ class TestAv1Encoder { codec_settings.width = kWidth; codec_settings.height = kHeight; codec_settings.maxFramerate = kFramerate; + codec_settings.maxBitrate = 1000; VideoEncoder::Settings encoder_settings( VideoEncoder::Capabilities(/*loss_notification=*/false), /*number_of_cores=*/1, /*max_payload_size=*/1200); @@ -271,6 +273,8 @@ INSTANTIATE_TEST_SUITE_P( Svc, LibaomAv1SvcTest, Values(SvcTestParam{std::make_unique, + /*num_frames_to_generate=*/4}, + SvcTestParam{std::make_unique, /*num_frames_to_generate=*/4})); } // namespace diff --git a/modules/video_coding/codecs/av1/scalability_structure_l1t2.cc b/modules/video_coding/codecs/av1/scalability_structure_l1t2.cc new file mode 100644 index 0000000000..cd58652dd0 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l1t2.cc @@ -0,0 +1,115 @@ +/* + * 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 { + using Builder = GenericFrameInfo::Builder; + FrameDependencyStructure structure; + structure.num_decode_targets = 2; + structure.num_chains = 1; + structure.decode_target_protected_by_chain = {0}; + structure.templates = { + Builder().T(0).Dtis("SS").ChainDiffs({0}).Build(), + Builder().T(0).Dtis("SS").ChainDiffs({2}).Fdiffs({2}).Build(), + Builder().T(1).Dtis("-D").ChainDiffs({1}).Fdiffs({1}).Build(), + }; + return structure; +} + +std::vector +ScalabilityStructureL1T2::NextFrameConfig(bool restart) { + if (restart) { + next_pattern_ = kKeyFrame; + } + std::vector result(1); + + switch (next_pattern_) { + case kKeyFrame: + result[0].id = 0; + result[0].temporal_id = 0; + result[0].is_keyframe = true; + result[0].buffers = {{/*id=*/0, /*references=*/false, /*updates=*/true}}; + next_pattern_ = kDeltaFrameT1; + break; + case kDeltaFrameT1: + result[0].id = 1; + result[0].temporal_id = 1; + result[0].is_keyframe = false; + result[0].buffers = {{/*id=*/0, /*references=*/true, /*updates=*/false}}; + next_pattern_ = kDeltaFrameT0; + break; + case kDeltaFrameT0: + result[0].id = 2; + result[0].temporal_id = 0; + result[0].is_keyframe = false; + result[0].buffers = {{/*id=*/0, /*references=*/true, /*updates=*/true}}; + next_pattern_ = kDeltaFrameT1; + break; + } + RTC_DCHECK(!result.empty()); + 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.is_keyframe) { + 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.temporal_id; + frame_info->encoder_buffers = std::move(config.buffers); + frame_info->decode_target_indications.assign(std::begin(kDtis[config.id]), + std::end(kDtis[config.id])); + frame_info->part_of_chain = {config.temporal_id == 0}; + return frame_info; +} + +} // namespace webrtc diff --git a/modules/video_coding/codecs/av1/scalability_structure_l1t2.h b/modules/video_coding/codecs/av1/scalability_structure_l1t2.h new file mode 100644 index 0000000000..72a9659c34 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l1t2.h @@ -0,0 +1,44 @@ +/* + * 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. + */ +#ifndef MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L1T2_H_ +#define MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L1T2_H_ + +#include + +#include "api/transport/rtp/dependency_descriptor.h" +#include "common_video/generic_frame_descriptor/generic_frame_info.h" +#include "modules/video_coding/codecs/av1/scalable_video_controller.h" + +namespace webrtc { + +class ScalabilityStructureL1T2 : public ScalableVideoController { + public: + ~ScalabilityStructureL1T2() override; + + StreamLayersConfig StreamConfig() const override; + FrameDependencyStructure DependencyStructure() const override; + + std::vector NextFrameConfig(bool restart) override; + absl::optional OnEncodeDone( + LayerFrameConfig config) override; + + private: + enum FramePattern { + kKeyFrame, + kDeltaFrameT1, + kDeltaFrameT0, + }; + + FramePattern next_pattern_ = kKeyFrame; +}; + +} // namespace webrtc + +#endif // MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L1T2_H_