text: /*
   *  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 <stddef.h>
  #include <stdint.h>
  
  #include <functional>
  #include <memory>
  #include <ostream>
  #include <string>
  
  #include "absl/types/optional.h"
  #include "api/transport/rtp/dependency_descriptor.h"
  #include "api/video/video_frame_type.h"
  #include "modules/video_coding/chain_diff_calculator.h"
  #include "modules/video_coding/codecs/av1/scalability_structure_l1t2.h"
  #include "modules/video_coding/codecs/av1/scalability_structure_l1t3.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_l3t1.h"
  #include "modules/video_coding/codecs/av1/scalability_structure_l3t3.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"
  #include "test/gmock.h"
  #include "test/gtest.h"
  
  namespace webrtc {
  namespace {
  
  using ::testing::AllOf;
  using ::testing::Contains;
  using ::testing::Each;
  using ::testing::Field;
  using ::testing::Ge;
  using ::testing::IsEmpty;
  using ::testing::Le;
  using ::testing::Lt;
  using ::testing::Not;
  using ::testing::SizeIs;
  using ::testing::TestWithParam;
  using ::testing::Values;
  
  struct SvcTestParam {
    friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) {
      return os << param.name;
    }
  
    std::string name;
    std::function<std::unique_ptr<ScalableVideoController>()> svc_factory;
    int num_temporal_units;
  };
  
  class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {
   public:
    std::vector<GenericFrameInfo> GenerateAllFrames() {
      std::vector<GenericFrameInfo> frames;
  
      FrameDependenciesCalculator frame_deps_calculator;
      ChainDiffCalculator chain_diff_calculator;
      std::unique_ptr<ScalableVideoController> structure_controller =
          GetParam().svc_factory();
      FrameDependencyStructure structure =
          structure_controller->DependencyStructure();
      for (int i = 0; i < GetParam().num_temporal_units; ++i) {
        for (auto& layer_frame :
             structure_controller->NextFrameConfig(/*reset=*/false)) {
          int64_t frame_id = static_cast<int64_t>(frames.size());
          bool is_keyframe = layer_frame.IsKeyframe();
          absl::optional<GenericFrameInfo> frame_info =
              structure_controller->OnEncodeDone(std::move(layer_frame));
          EXPECT_TRUE(frame_info.has_value());
          if (is_keyframe) {
            chain_diff_calculator.Reset(frame_info->part_of_chain);
          }
          frame_info->chain_diffs =
              chain_diff_calculator.From(frame_id, frame_info->part_of_chain);
          for (int64_t base_frame_id : frame_deps_calculator.FromBuffersUsage(
                   is_keyframe ? VideoFrameType::kVideoFrameKey
                               : VideoFrameType::kVideoFrameDelta,
                   frame_id, frame_info->encoder_buffers)) {
            EXPECT_LT(base_frame_id, frame_id);
            EXPECT_GE(base_frame_id, 0);
            frame_info->frame_diffs.push_back(frame_id - base_frame_id);
          }
  
          frames.push_back(*std::move(frame_info));
        }
      }
      return frames;
    }
  };
  
  TEST_P(ScalabilityStructureTest,
         NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    EXPECT_GT(structure.num_decode_targets, 0);
    EXPECT_LE(structure.num_decode_targets,
              DependencyDescriptor::kMaxDecodeTargets);
    EXPECT_GE(structure.num_chains, 0);
    EXPECT_LE(structure.num_chains, structure.num_decode_targets);
    if (structure.num_chains == 0) {
      EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty());
    } else {
      EXPECT_THAT(structure.decode_target_protected_by_chain,
                  AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)),
                        Each(Le(structure.num_chains))));
    }
    EXPECT_THAT(structure.templates,
                SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates})));
  }
  
  TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    ASSERT_THAT(structure.templates, Not(IsEmpty()));
    const auto& first_templates = structure.templates.front();
    EXPECT_EQ(first_templates.spatial_id, 0);
    EXPECT_EQ(first_templates.temporal_id, 0);
    for (size_t i = 1; i < structure.templates.size(); ++i) {
      const auto& prev_template = structure.templates[i - 1];
      const auto& next_template = structure.templates[i];
      if (next_template.spatial_id == prev_template.spatial_id &&
          next_template.temporal_id == prev_template.temporal_id) {
        // Same layer, next_layer_idc == 0
      } else if (next_template.spatial_id == prev_template.spatial_id &&
                 next_template.temporal_id == prev_template.temporal_id + 1) {
        // Next temporal layer, next_layer_idc == 1
      } else if (next_template.spatial_id == prev_template.spatial_id + 1 &&
                 next_template.temporal_id == 0) {
        // Next spatial layer, next_layer_idc == 2
      } else {
        // everything else is invalid.
        ADD_FAILURE() << "Invalid templates order. Template #" << i
                      << " with layer (" << next_template.spatial_id << ","
                      << next_template.temporal_id
                      << ") follows template with layer ("
                      << prev_template.spatial_id << ","
                      << prev_template.temporal_id << ").";
      }
    }
  }
  
  TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    EXPECT_THAT(
        structure.templates,
        Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
                         SizeIs(structure.num_decode_targets)),
                   Field(&FrameDependencyTemplate::chain_diffs,
                         SizeIs(structure.num_chains)))));
  }
  
  TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
    for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
      const auto& frame = frame_infos[frame_id];
      EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id;
      EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id;
      EXPECT_THAT(frame.decode_target_indications,
                  SizeIs(structure.num_decode_targets))
          << " for frame " << frame_id;
      EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains))
          << " for frame " << frame_id;
    }
  }
  
  TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
    for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
      EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
          << " for frame " << frame_id;
    }
  }
  
  TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
    std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
    int64_t num_frames = frame_infos.size();
  
    for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
      const auto& frame = frame_infos[frame_id];
      for (int frame_diff : frame.frame_diffs) {
        int64_t base_frame_id = frame_id - frame_diff;
        const auto& base_frame = frame_infos[base_frame_id];
        EXPECT_GE(frame.spatial_id, base_frame.spatial_id)
            << "Frame " << frame_id << " depends on frame " << base_frame_id;
        EXPECT_GE(frame.temporal_id, base_frame.temporal_id)
            << "Frame " << frame_id << " depends on frame " << base_frame_id;
      }
    }
  }
  
  TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
    std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
    int64_t num_frames = frame_infos.size();
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
  
    for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
      for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
        const auto& frame = frame_infos[frame_id];
        if (frame.decode_target_indications[dt] ==
            DecodeTargetIndication::kNotPresent) {
          continue;
        }
        for (int frame_diff : frame.frame_diffs) {
          int64_t base_frame_id = frame_id - frame_diff;
          const auto& base_frame = frame_infos[base_frame_id];
          EXPECT_NE(base_frame.decode_target_indications[dt],
                    DecodeTargetIndication::kNotPresent)
              << "Frame " << frame_id << " depends on frame " << base_frame_id
              << " that is not part of decode target#" << dt;
          EXPECT_NE(base_frame.decode_target_indications[dt],
                    DecodeTargetIndication::kDiscardable)
              << "Frame " << frame_id << " depends on frame " << base_frame_id
              << " that is discardable for decode target#" << dt;
        }
      }
    }
  }
  
  TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
    FrameDependencyStructure structure =
        GetParam().svc_factory()->DependencyStructure();
    std::vector<GenericFrameInfo> frame_infos = GenerateAllFrames();
    int64_t num_frames = frame_infos.size();
    std::vector<std::set<int64_t>> full_deps(num_frames);
  
    // For each frame calculate set of all frames it depends on, both directly and
    // indirectly.
    for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
      std::set<int64_t> all_base_frames;
      for (int frame_diff : frame_infos[frame_id].frame_diffs) {
        int64_t base_frame_id = frame_id - frame_diff;
        all_base_frames.insert(base_frame_id);
        const auto& indirect = full_deps[base_frame_id];
        all_base_frames.insert(indirect.begin(), indirect.end());
      }
      full_deps[frame_id] = std::move(all_base_frames);
    }
  
    // Now check the switch indication: frames after the switch indication mustn't
    // depend on any addition frames before the switch indications.
    for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
      for (int64_t switch_frame_id = 0; switch_frame_id < num_frames;
           ++switch_frame_id) {
        if (frame_infos[switch_frame_id].decode_target_indications[dt] !=
            DecodeTargetIndication::kSwitch) {
          continue;
        }
        for (int64_t later_frame_id = switch_frame_id + 1;
             later_frame_id < num_frames; ++later_frame_id) {
          if (frame_infos[later_frame_id].decode_target_indications[dt] ==
              DecodeTargetIndication::kNotPresent) {
            continue;
          }
          for (int frame_diff : frame_infos[later_frame_id].frame_diffs) {
            int64_t early_frame_id = later_frame_id - frame_diff;
            if (early_frame_id < switch_frame_id) {
              EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id))
                  << "For decode target #" << dt << " frame " << later_frame_id
                  << " depends on the frame " << early_frame_id
                  << " that switch indication frame " << switch_frame_id
                  << " doesn't directly on indirectly depend on.";
            }
          }
        }
      }
    }
  }
  
  INSTANTIATE_TEST_SUITE_P(
      Svc,
      ScalabilityStructureTest,
      Values(SvcTestParam{"L1T2", std::make_unique<ScalabilityStructureL1T2>,
                          /*num_temporal_units=*/4},
             SvcTestParam{"L1T3", std::make_unique<ScalabilityStructureL1T3>,
                          /*num_temporal_units=*/8},
             SvcTestParam{"L2T1", std::make_unique<ScalabilityStructureL2T1>,
                          /*num_temporal_units=*/3},
             SvcTestParam{"L2T1Key",
                          std::make_unique<ScalabilityStructureL2T1Key>,
                          /*num_temporal_units=*/3},
             SvcTestParam{"L3T1", std::make_unique<ScalabilityStructureL3T1>,
                          /*num_temporal_units=*/3},
             SvcTestParam{"L3T3", std::make_unique<ScalabilityStructureL3T3>,
                          /*num_temporal_units=*/8},
             SvcTestParam{"S2T1", std::make_unique<ScalabilityStructureS2T1>,
                          /*num_temporal_units=*/3},
             SvcTestParam{"L2T2", std::make_unique<ScalabilityStructureL2T2>,
                          /*num_temporal_units=*/4},
             SvcTestParam{"L2T2Key",
                          std::make_unique<ScalabilityStructureL2T2Key>,
                          /*num_temporal_units=*/4},
             SvcTestParam{"L2T2KeyShift",
                          std::make_unique<ScalabilityStructureL2T2KeyShift>,
                          /*num_temporal_units=*/4}),
      [](const testing::TestParamInfo<SvcTestParam>& info) {
        return info.param.name;
      });
  
  }  // namespace
  }  // namespace webrtc
  