diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn index 41fd163427..36bca68f21 100644 --- a/modules/video_coding/codecs/av1/BUILD.gn +++ b/modules/video_coding/codecs/av1/BUILD.gn @@ -59,6 +59,12 @@ rtc_source_set("scalability_structures") { "scalability_structure_l2t1.h", "scalability_structure_l2t1_key.cc", "scalability_structure_l2t1_key.h", + "scalability_structure_l2t2.cc", + "scalability_structure_l2t2.h", + "scalability_structure_l2t2_key.cc", + "scalability_structure_l2t2_key.h", + "scalability_structure_l2t2_key_shift.cc", + "scalability_structure_l2t2_key_shift.h", "scalability_structure_s2t1.cc", "scalability_structure_s2t1.h", ] diff --git a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc index 5316a39fc1..90c9e67dd6 100644 --- a/modules/video_coding/codecs/av1/libaom_av1_unittest.cc +++ b/modules/video_coding/codecs/av1/libaom_av1_unittest.cc @@ -24,6 +24,9 @@ #include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h" #include "modules/video_coding/codecs/av1/scalability_structure_l2t1.h" #include "modules/video_coding/codecs/av1/scalability_structure_l2t1_key.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h" #include "modules/video_coding/codecs/av1/scalability_structure_s2t1.h" #include "modules/video_coding/codecs/av1/scalable_video_controller.h" #include "modules/video_coding/codecs/av1/scalable_video_controller_no_layering.h" @@ -285,7 +288,13 @@ INSTANTIATE_TEST_SUITE_P( SvcTestParam{std::make_unique, /*num_frames_to_generate=*/3}, SvcTestParam{std::make_unique, - /*num_frames_to_generate=*/3})); + /*num_frames_to_generate=*/3}, + SvcTestParam{std::make_unique, + /*num_frames_to_generate=*/4}, + SvcTestParam{std::make_unique, + /*num_frames_to_generate=*/4}, + SvcTestParam{std::make_unique, + /*num_frames_to_generate=*/4})); } // namespace } // namespace webrtc diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2.cc b/modules/video_coding/codecs/av1/scalability_structure_l2t2.cc new file mode 100644 index 0000000000..30874d44da --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2.cc @@ -0,0 +1,175 @@ +/* + * 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_l2t2.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 auto kRequired = DecodeTargetIndication::kRequired; + +// decode targets: S0T0, S0T1, S1T0, S1T1 +constexpr DecodeTargetIndication kDtis[6][4] = { + {kSwitch, kSwitch, kSwitch, kSwitch}, // kKey, S0 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kKey, S1 + {kNotPresent, kDiscardable, kNotPresent, kRequired}, // kDeltaT1, S0 + {kNotPresent, kNotPresent, kNotPresent, kDiscardable}, // kDeltaT1, S1 + {kSwitch, kSwitch, kRequired, kRequired}, // kDeltaT0, S0 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kDeltaT0, S1 +}; + +} // namespace + +ScalabilityStructureL2T2::~ScalabilityStructureL2T2() = default; + +ScalableVideoController::StreamLayersConfig +ScalabilityStructureL2T2::StreamConfig() const { + StreamLayersConfig result; + result.num_spatial_layers = 2; + result.num_temporal_layers = 2; + return result; +} + +FrameDependencyStructure ScalabilityStructureL2T2::DependencyStructure() const { + using Builder = GenericFrameInfo::Builder; + FrameDependencyStructure structure; + structure.num_decode_targets = 4; + structure.num_chains = 2; + structure.decode_target_protected_by_chain = {0, 0, 1, 1}; + structure.templates = { + Builder().S(0).T(0).Dtis("SSSS").ChainDiffs({0, 0}).Build(), + Builder().S(0).T(0).Dtis("SSRR").Fdiffs({4}).ChainDiffs({4, 3}).Build(), + Builder().S(0).T(1).Dtis("-D-R").Fdiffs({2}).ChainDiffs({2, 1}).Build(), + Builder().S(1).T(0).Dtis("--SS").Fdiffs({1}).ChainDiffs({1, 1}).Build(), + Builder() + .S(1) + .T(0) + .Dtis("--SS") + .Fdiffs({4, 1}) + .ChainDiffs({1, 1}) + .Build(), + Builder() + .S(1) + .T(1) + .Dtis("---D") + .Fdiffs({2, 1}) + .ChainDiffs({3, 2}) + .Build(), + }; + return structure; +} + +ScalableVideoController::LayerFrameConfig +ScalabilityStructureL2T2::KeyFrameConfig() const { + LayerFrameConfig result; + result.id = 0; + result.is_keyframe = true; + result.spatial_id = 0; + result.temporal_id = 0; + result.buffers = {{/*id=*/0, /*referenced=*/false, /*updated=*/true}}; + return result; +} + +std::vector +ScalabilityStructureL2T2::NextFrameConfig(bool restart) { + if (restart) { + next_pattern_ = kKey; + } + std::vector result(2); + + // Buffer0 keeps latest S0T0 frame, + // Buffer1 keeps latest S1T0 frame. + // Buffer2 keeps latest S0T1 frame. + switch (next_pattern_) { + case kKey: + result[0] = KeyFrameConfig(); + + result[1].id = 1; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}, + {/*id=*/1, /*referenced=*/false, /*updated=*/true}}; + + next_pattern_ = kDeltaT1; + break; + case kDeltaT1: + result[0].id = 2; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 1; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}, + {/*id=*/2, /*referenced=*/false, /*updated=*/true}}; + + result[1].id = 3; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 1; + result[1].buffers = {{/*id=*/2, /*referenced=*/true, /*updated=*/false}, + {/*id=*/1, /*referenced=*/true, /*updated=*/false}}; + + next_pattern_ = kDeltaT0; + break; + case kDeltaT0: + result[0].id = 4; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 0; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/true}}; + + result[1].id = 5; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}, + {/*id=*/1, /*referenced=*/true, /*updated=*/true}}; + + next_pattern_ = kDeltaT1; + break; + } + return result; +} + +absl::optional ScalabilityStructureL2T2::OnEncodeDone( + LayerFrameConfig config) { + if (config.is_keyframe) { + config = KeyFrameConfig(); + } + + 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->spatial_id = config.spatial_id; + 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])); + if (config.temporal_id == 0) { + frame_info->part_of_chain = {config.spatial_id == 0, true}; + } else { + frame_info->part_of_chain = {false, false}; + } + return frame_info; +} + +} // namespace webrtc diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2.h b/modules/video_coding/codecs/av1/scalability_structure_l2t2.h new file mode 100644 index 0000000000..dbf5036c1f --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2.h @@ -0,0 +1,53 @@ +/* + * 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_L2T2_H_ +#define MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_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 { + +// S1T1 0 0 +// /| /| / +// S1T0 0-+-0-+-0 +// | | | | | ... +// S0T1 | 0 | 0 | +// |/ |/ |/ +// S0T0 0---0---0-- +// Time-> 0 1 2 3 4 +class ScalabilityStructureL2T2 : public ScalableVideoController { + public: + ~ScalabilityStructureL2T2() override; + + StreamLayersConfig StreamConfig() const override; + FrameDependencyStructure DependencyStructure() const override; + + std::vector NextFrameConfig(bool restart) override; + absl::optional OnEncodeDone( + LayerFrameConfig config) override; + + private: + enum FramePattern { + kKey, + kDeltaT1, + kDeltaT0, + }; + LayerFrameConfig KeyFrameConfig() const; + + FramePattern next_pattern_ = kKey; +}; + +} // namespace webrtc + +#endif // MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_H_ diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.cc b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.cc new file mode 100644 index 0000000000..02fd408c96 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.cc @@ -0,0 +1,162 @@ +/* + * 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_l2t2_key.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; + +// decode targets: S0T0, S0T1, S1T0, S1T1 +constexpr DecodeTargetIndication kDtis[6][4] = { + {kSwitch, kSwitch, kSwitch, kSwitch}, // kKey, S0 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kKey, S1 + {kNotPresent, kDiscardable, kNotPresent, kNotPresent}, // kDeltaT1, S0 + {kNotPresent, kNotPresent, kNotPresent, kDiscardable}, // kDeltaT1, S1 + {kSwitch, kSwitch, kNotPresent, kNotPresent}, // kDeltaT0, S0 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kDeltaT0, S1 +}; + +} // namespace + +ScalabilityStructureL2T2Key::~ScalabilityStructureL2T2Key() = default; + +ScalableVideoController::StreamLayersConfig +ScalabilityStructureL2T2Key::StreamConfig() const { + StreamLayersConfig result; + result.num_spatial_layers = 2; + result.num_temporal_layers = 2; + return result; +} + +FrameDependencyStructure ScalabilityStructureL2T2Key::DependencyStructure() + const { + using Builder = GenericFrameInfo::Builder; + FrameDependencyStructure structure; + structure.num_decode_targets = 4; + structure.num_chains = 2; + structure.decode_target_protected_by_chain = {0, 0, 1, 1}; + structure.templates = { + Builder().S(0).T(0).Dtis("SSSS").ChainDiffs({0, 0}).Build(), + Builder().S(0).T(0).Dtis("SS--").Fdiffs({4}).ChainDiffs({4, 3}).Build(), + Builder().S(0).T(1).Dtis("-D--").Fdiffs({2}).ChainDiffs({2, 1}).Build(), + Builder().S(1).T(0).Dtis("--SS").Fdiffs({1}).ChainDiffs({1, 1}).Build(), + Builder().S(1).T(0).Dtis("--SS").Fdiffs({4}).ChainDiffs({1, 4}).Build(), + Builder().S(1).T(1).Dtis("---D").Fdiffs({2}).ChainDiffs({3, 2}).Build(), + }; + return structure; +} + +ScalableVideoController::LayerFrameConfig +ScalabilityStructureL2T2Key::KeyFrameConfig() const { + LayerFrameConfig result; + result.id = 0; + result.is_keyframe = true; + result.spatial_id = 0; + result.temporal_id = 0; + result.buffers = {{/*id=*/0, /*referenced=*/false, /*updated=*/true}}; + return result; +} + +std::vector +ScalabilityStructureL2T2Key::NextFrameConfig(bool restart) { + if (restart) { + next_pattern_ = kKey; + } + std::vector result(2); + + // Buffer0 keeps latest S0T0 frame, + // Buffer1 keeps latest S1T0 frame. + switch (next_pattern_) { + case kKey: + result[0] = KeyFrameConfig(); + + result[1].id = 1; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}, + {/*id=*/1, /*referenced=*/false, /*updated=*/true}}; + + next_pattern_ = kDeltaT1; + break; + case kDeltaT1: + result[0].id = 2; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 1; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}}; + + result[1].id = 3; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 1; + result[1].buffers = {{/*id=*/1, /*referenced=*/true, /*updated=*/false}}; + + next_pattern_ = kDeltaT0; + break; + case kDeltaT0: + result[0].id = 4; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 0; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/true}}; + + result[1].id = 5; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/1, /*referenced=*/true, /*updated=*/true}}; + + next_pattern_ = kDeltaT1; + break; + } + return result; +} + +absl::optional ScalabilityStructureL2T2Key::OnEncodeDone( + LayerFrameConfig config) { + if (config.is_keyframe) { + config = KeyFrameConfig(); + } + + 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->spatial_id = config.spatial_id; + 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])); + if (config.is_keyframe) { + frame_info->part_of_chain = {true, true}; + } else if (config.temporal_id == 0) { + frame_info->part_of_chain = {config.spatial_id == 0, + config.spatial_id == 1}; + } else { + frame_info->part_of_chain = {false, false}; + } + return frame_info; +} + +} // namespace webrtc diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h new file mode 100644 index 0000000000..9adfcbcd58 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h @@ -0,0 +1,53 @@ +/* + * 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_L2T2_KEY_H_ +#define MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_KEY_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 { + +// S1T1 0 0 +// / / / +// S1T0 0---0---0 +// | ... +// S0T1 | 0 0 +// |/ / / +// S0T0 0---0---0 +// Time-> 0 1 2 3 4 +class ScalabilityStructureL2T2Key : public ScalableVideoController { + public: + ~ScalabilityStructureL2T2Key() override; + + StreamLayersConfig StreamConfig() const override; + FrameDependencyStructure DependencyStructure() const override; + + std::vector NextFrameConfig(bool restart) override; + absl::optional OnEncodeDone( + LayerFrameConfig config) override; + + private: + enum FramePattern { + kKey, + kDeltaT1, + kDeltaT0, + }; + LayerFrameConfig KeyFrameConfig() const; + + FramePattern next_pattern_ = kKey; +}; + +} // namespace webrtc + +#endif // MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_KEY_H_ diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.cc b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.cc new file mode 100644 index 0000000000..f268a157e9 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.cc @@ -0,0 +1,163 @@ +/* + * 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_l2t2_key_shift.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; + +// decode targets: S0T0, S0T1, S1T0, S1T1 +constexpr DecodeTargetIndication kDtis[6][4] = { + {kSwitch, kSwitch, kSwitch, kSwitch}, // kKey, S0T0 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kKey, S1T0 + {kSwitch, kSwitch, kNotPresent, kNotPresent}, // kDelta0, S0T0 + {kNotPresent, kNotPresent, kNotPresent, kDiscardable}, // kDelta0, S1T1 + {kNotPresent, kDiscardable, kNotPresent, kNotPresent}, // kDelta1, S0T1 + {kNotPresent, kNotPresent, kSwitch, kSwitch}, // kDelta1, S1T0 +}; + +} // namespace + +ScalabilityStructureL2T2KeyShift::~ScalabilityStructureL2T2KeyShift() = default; + +ScalableVideoController::StreamLayersConfig +ScalabilityStructureL2T2KeyShift::StreamConfig() const { + StreamLayersConfig result; + result.num_spatial_layers = 2; + result.num_temporal_layers = 2; + return result; +} + +FrameDependencyStructure ScalabilityStructureL2T2KeyShift::DependencyStructure() + const { + using Builder = GenericFrameInfo::Builder; + FrameDependencyStructure structure; + structure.num_decode_targets = 4; + structure.num_chains = 2; + structure.decode_target_protected_by_chain = {0, 0, 1, 1}; + structure.templates = { + Builder().S(0).T(0).Dtis("SSSS").ChainDiffs({0, 0}).Build(), + Builder().S(0).T(0).Dtis("SS--").Fdiffs({2}).ChainDiffs({2, 1}).Build(), + Builder().S(0).T(0).Dtis("SS--").Fdiffs({4}).ChainDiffs({4, 1}).Build(), + Builder().S(0).T(1).Dtis("-D--").Fdiffs({2}).ChainDiffs({2, 3}).Build(), + Builder().S(1).T(0).Dtis("--SS").Fdiffs({1}).ChainDiffs({1, 1}).Build(), + Builder().S(1).T(0).Dtis("--SS").Fdiffs({4}).ChainDiffs({3, 4}).Build(), + Builder().S(1).T(1).Dtis("---D").Fdiffs({2}).ChainDiffs({1, 2}).Build(), + }; + return structure; +} + +ScalableVideoController::LayerFrameConfig +ScalabilityStructureL2T2KeyShift::KeyFrameConfig() const { + LayerFrameConfig result; + result.id = 0; + result.is_keyframe = true; + result.spatial_id = 0; + result.temporal_id = 0; + result.buffers = {{/*id=*/0, /*referenced=*/false, /*updated=*/true}}; + return result; +} + +std::vector +ScalabilityStructureL2T2KeyShift::NextFrameConfig(bool restart) { + if (restart) { + next_pattern_ = kKey; + } + std::vector result(2); + + // Buffer0 keeps latest S0T0 frame, + // Buffer1 keeps latest S1T0 frame. + switch (next_pattern_) { + case kKey: + result[0] = KeyFrameConfig(); + + result[1].id = 1; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}, + {/*id=*/1, /*referenced=*/false, /*updated=*/true}}; + + next_pattern_ = kDelta0; + break; + case kDelta0: + result[0].id = 2; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 0; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/true}}; + + result[1].id = 3; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 1; + result[1].buffers = {{/*id=*/1, /*referenced=*/true, /*updated=*/false}}; + + next_pattern_ = kDelta1; + break; + case kDelta1: + result[0].id = 4; + result[0].is_keyframe = false; + result[0].spatial_id = 0; + result[0].temporal_id = 1; + result[0].buffers = {{/*id=*/0, /*referenced=*/true, /*updated=*/false}}; + + result[1].id = 5; + result[1].is_keyframe = false; + result[1].spatial_id = 1; + result[1].temporal_id = 0; + result[1].buffers = {{/*id=*/1, /*referenced=*/true, /*updated=*/true}}; + + next_pattern_ = kDelta0; + break; + } + return result; +} + +absl::optional ScalabilityStructureL2T2KeyShift::OnEncodeDone( + LayerFrameConfig config) { + if (config.is_keyframe) { + config = KeyFrameConfig(); + } + + 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->spatial_id = config.spatial_id; + 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])); + if (config.is_keyframe) { + frame_info->part_of_chain = {true, true}; + } else if (config.temporal_id == 0) { + frame_info->part_of_chain = {config.spatial_id == 0, + config.spatial_id == 1}; + } else { + frame_info->part_of_chain = {false, false}; + } + return frame_info; +} + +} // namespace webrtc diff --git a/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h new file mode 100644 index 0000000000..1b18bd7c17 --- /dev/null +++ b/modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h @@ -0,0 +1,53 @@ +/* + * 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_L2T2_KEY_SHIFT_H_ +#define MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_KEY_SHIFT_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 { + +// S1T1 0 0 +// / / / +// S1T0 0---0---0 +// | ... +// S0T1 | 0 0 +// | / / +// S0T0 0-0---0-- +// Time-> 0 1 2 3 4 +class ScalabilityStructureL2T2KeyShift : public ScalableVideoController { + public: + ~ScalabilityStructureL2T2KeyShift() override; + + StreamLayersConfig StreamConfig() const override; + FrameDependencyStructure DependencyStructure() const override; + + std::vector NextFrameConfig(bool restart) override; + absl::optional OnEncodeDone( + LayerFrameConfig config) override; + + private: + enum FramePattern { + kKey, + kDelta0, + kDelta1, + }; + LayerFrameConfig KeyFrameConfig() const; + + FramePattern next_pattern_ = kKey; +}; + +} // namespace webrtc + +#endif // MODULES_VIDEO_CODING_CODECS_AV1_SCALABILITY_STRUCTURE_L2T2_KEY_SHIFT_H_ diff --git a/modules/video_coding/codecs/av1/scalability_structure_unittest.cc b/modules/video_coding/codecs/av1/scalability_structure_unittest.cc index 37e9d716d3..29aac5dd2b 100644 --- a/modules/video_coding/codecs/av1/scalability_structure_unittest.cc +++ b/modules/video_coding/codecs/av1/scalability_structure_unittest.cc @@ -22,6 +22,9 @@ #include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h" #include "modules/video_coding/codecs/av1/scalability_structure_l2t1.h" #include "modules/video_coding/codecs/av1/scalability_structure_l2t1_key.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key.h" +#include "modules/video_coding/codecs/av1/scalability_structure_l2t2_key_shift.h" #include "modules/video_coding/codecs/av1/scalability_structure_s2t1.h" #include "modules/video_coding/codecs/av1/scalable_video_controller.h" #include "modules/video_coding/frame_dependencies_calculator.h" @@ -287,7 +290,15 @@ INSTANTIATE_TEST_SUITE_P( std::make_unique, /*num_temporal_units=*/3}, SvcTestParam{"S2T1", std::make_unique, - /*num_temporal_units=*/3}), + /*num_temporal_units=*/3}, + SvcTestParam{"L2T2", std::make_unique, + /*num_temporal_units=*/4}, + SvcTestParam{"L2T2Key", + std::make_unique, + /*num_temporal_units=*/4}, + SvcTestParam{"L2T2KeyShift", + std::make_unique, + /*num_temporal_units=*/4}), [](const testing::TestParamInfo& info) { return info.param.name; });