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