Shaka Packager SDK
bandwidth_estimator.cc
1 // Copyright 2014 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/mpd/base/bandwidth_estimator.h>
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <numeric>
12 
13 #include <absl/log/check.h>
14 #include <absl/log/log.h>
15 
16 #include <packager/macros/logging.h>
17 
18 namespace shaka {
19 
20 BandwidthEstimator::BandwidthEstimator() = default;
21 
22 BandwidthEstimator::~BandwidthEstimator() = default;
23 
24 void BandwidthEstimator::AddBlock(uint64_t size_in_bytes, double duration) {
25  if (size_in_bytes == 0 || duration == 0) {
26  LOG(WARNING) << "Ignore block with size=" << size_in_bytes
27  << ", duration=" << duration;
28  return;
29  }
30 
31  const int kBitsInByte = 8;
32  const uint64_t size_in_bits = size_in_bytes * kBitsInByte;
33  total_size_in_bits_ += size_in_bits;
34  total_duration_ += duration;
35 
36  const size_t kTargetDurationThreshold = 10;
37  if (initial_blocks_.size() < kTargetDurationThreshold) {
38  initial_blocks_.push_back({size_in_bits, duration});
39  return;
40  }
41 
42  if (target_block_duration_ == 0) {
43  // Use the average duration as the target block duration. It will be used
44  // to filter small blocks from bandwidth calculation.
45  target_block_duration_ = GetAverageBlockDuration();
46  for (const Block& block : initial_blocks_) {
47  max_bitrate_ =
48  std::max(max_bitrate_, GetBitrate(block, target_block_duration_));
49  }
50  return;
51  }
52  max_bitrate_ = std::max(max_bitrate_, GetBitrate({size_in_bits, duration},
53  target_block_duration_));
54 }
55 
56 uint64_t BandwidthEstimator::Estimate() const {
57  if (total_duration_ == 0)
58  return 0;
59  return static_cast<uint64_t>(ceil(total_size_in_bits_ / total_duration_));
60 }
61 
62 uint64_t BandwidthEstimator::Max() const {
63  if (max_bitrate_ != 0)
64  return max_bitrate_;
65 
66  // We don't have the |target_block_duration_| yet. Calculate a target
67  // duration from the current available blocks.
68  DCHECK(target_block_duration_ == 0);
69  const double target_block_duration = GetAverageBlockDuration();
70 
71  // Calculate maximum bitrate with the target duration calculated above.
72  uint64_t max_bitrate = 0;
73  for (const Block& block : initial_blocks_) {
74  max_bitrate =
75  std::max(max_bitrate, GetBitrate(block, target_block_duration));
76  }
77  return max_bitrate;
78 }
79 
80 double BandwidthEstimator::GetAverageBlockDuration() const {
81  if (initial_blocks_.empty())
82  return 0.0;
83  const double sum =
84  std::accumulate(initial_blocks_.begin(), initial_blocks_.end(), 0.0,
85  [](double duration, const Block& block) {
86  return duration + block.duration;
87  });
88  return sum / initial_blocks_.size();
89 }
90 
91 uint64_t BandwidthEstimator::GetBitrate(const Block& block,
92  double target_block_duration) const {
93  if (block.duration < 0.5 * target_block_duration) {
94  // https://tools.ietf.org/html/rfc8216#section-4.1
95  // The peak segment bit rate of a Media Playlist is the largest bit rate of
96  // any continuous set of segments whose total duration is between 0.5
97  // and 1.5 times the target duration.
98  // Only the short segments are excluded here as our media playlist generator
99  // sets the target duration in the playlist to the largest segment duration.
100  // So although the segment duration could be 1.5 times the user provided
101  // segment duration, it will never be larger than the actual target
102  // duration.
103  //
104  // We also apply the same exclusion to the bandwidth computation for DASH as
105  // the bitrate for the short segment is not a good signal for peak
106  // bandwidth.
107  // See https://github.com/shaka-project/shaka-packager/issues/498 for
108  // details.
109  VLOG(1) << "Exclude short segment (duration " << block.duration
110  << ", target_duration " << target_block_duration
111  << ") in peak bandwidth computation.";
112  return 0;
113  }
114  return static_cast<uint64_t>(ceil(block.size_in_bits / block.duration));
115 }
116 
117 } // namespace shaka
void AddBlock(uint64_t size_in_bytes, double duration)
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66