OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 * | |
10 */ | |
11 | |
12 #include "webrtc/modules/video_coding/utility/simulcast_state.h" | |
13 | |
14 #include <algorithm> | |
15 #include <numeric> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 | |
19 namespace webrtc { | |
20 | |
21 SimulcastState::SimulcastState(const VideoCodec& codec) | |
22 : codec_(codec), | |
23 sum_max_bitrate_(0), | |
24 sum_target_bitrate_(0), | |
25 sum_allocated_bitrate_(0) { | |
26 RTC_DCHECK_EQ(kVideoCodecVP8, codec_.codecType) | |
27 << "Only VP8 Simulcast currently supported."; | |
28 if (codec_.numberOfSimulcastStreams == 0) { | |
29 codec_.numberOfSimulcastStreams = 1; | |
30 codec_.simulcastStream[0] = { | |
31 codec_.width, | |
32 codec_.height, | |
33 codec_.codecSpecific.VP8.numberOfTemporalLayers, | |
34 codec_.maxBitrate, | |
35 codec_.targetBitrate, | |
36 codec_.minBitrate, | |
37 codec_.qpMax}; | |
38 } | |
39 int start_bitrate_left = codec_.startBitrate; | |
40 for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) { | |
41 sum_max_bitrate_ += codec_.simulcastStream[i].maxBitrate; | |
42 int target_bitrate = codec_.simulcastStream[i].targetBitrate; | |
43 sum_target_bitrate_ += target_bitrate; | |
44 int start_bitrate = std::min(start_bitrate_left, target_bitrate); | |
45 streams_.push_back(Stream(i, &codec_, start_bitrate)); | |
46 start_bitrate_left = std::max(0, start_bitrate_left - start_bitrate); | |
47 } | |
48 if (sum_max_bitrate_ == 0) { | |
49 // All but the last stream is disabled. | |
50 streams_.clear(); | |
51 streams_.push_back(Stream(0, &codec_, codec_.startBitrate)); | |
52 sum_target_bitrate_ = codec_.targetBitrate; | |
53 } | |
54 sum_allocated_bitrate_ = sum_target_bitrate_; | |
55 AllocateBitrate(codec_.startBitrate); | |
56 } | |
57 | |
58 SimulcastState::~SimulcastState() {} | |
59 | |
60 int SimulcastState::AllocateBitrate(int target_bitrate_kbps) { | |
61 // Always allocate enough bitrate for the minimum bitrate of the first layer. | |
62 // Suspending below min bitrate is controlled outside the codec implementation | |
63 // and is not overriden by this. | |
64 sum_allocated_bitrate_ = std::max( | |
65 target_bitrate_kbps, static_cast<int>(streams_[0].config.minBitrate)); | |
66 int32_t bitrate_left = sum_allocated_bitrate_; | |
67 | |
68 // Allocate min -> target bitrates as long as we have bitrate to spend. | |
69 int last_active_stream = 0; | |
70 for (auto stream = streams_.begin(); stream != streams_.end(); ++stream) { | |
pbos-webrtc
2016/04/29 21:23:27
auto& stream : streams_, or auto& it
| |
71 stream->allocated_rate_kbps = 0; | |
72 int target_bitrate = | |
73 std::max(stream->config.targetBitrate, stream->config.minBitrate); | |
74 int allocated = IncreaseBitrateAllocation( | |
75 &*stream, std::min(bitrate_left, target_bitrate)); | |
76 bitrate_left -= allocated; | |
77 if (allocated <= 0 || last_active_stream < stream->idx - 1) { | |
78 // Not enough bitrate for this stream, or for some stream before this one; | |
pbos-webrtc
2016/04/29 21:23:27
Can you do disabling in a loop outside this one? T
| |
79 // disable it. | |
80 stream->sending = false; | |
81 stream->keyframe_request = false; | |
82 stream->allocated_rate_kbps = 0; | |
83 continue; // Continue disabling all streams above this one. | |
84 } | |
85 last_active_stream = stream->idx; | |
86 } | |
87 | |
88 // Spend additional bits on the highest-quality active layer, up to max | |
89 // bitrate. | |
90 // TODO(pbos): Consider spending additional bits on last_active_stream-1 down | |
91 // to 0 and not just the top layer when we have additional bitrate to spend. | |
92 if (bitrate_left > 0) { | |
93 Stream* highest_stream = &streams_[last_active_stream]; | |
pbos-webrtc
2016/04/29 21:23:27
put &streams_[...] inside the below call
| |
94 bitrate_left -= IncreaseBitrateAllocation(&*highest_stream, bitrate_left); | |
95 } | |
96 | |
97 sum_allocated_bitrate_ -= bitrate_left; | |
98 return sum_allocated_bitrate_; | |
99 } | |
100 | |
101 // Try to increase bitrate allocation of this stream by bitrate_kbps_delta, and | |
102 // return how much of that budget that was allocated, if any. | |
103 int SimulcastState::IncreaseBitrateAllocation(Stream* stream, | |
104 int bitrate_kbps_delta) { | |
105 int new_bitrate = stream->allocated_rate_kbps + bitrate_kbps_delta; | |
106 if (new_bitrate < static_cast<int>(stream->config.minBitrate)) | |
107 return 0; | |
108 | |
109 int allocated_bitrate = bitrate_kbps_delta; | |
110 const int max_bitrate = stream->config.maxBitrate; | |
111 if (max_bitrate > 0 && new_bitrate > max_bitrate) { | |
112 RTC_DCHECK_LE(stream->allocated_rate_kbps, new_bitrate); | |
113 allocated_bitrate -= new_bitrate - max_bitrate; | |
114 new_bitrate = max_bitrate; | |
115 } | |
116 | |
117 if (!stream->sending && new_bitrate > 0) { | |
118 // This stream was previously disabled, request a keyframe. | |
119 stream->sending = true; | |
120 stream->keyframe_request = true; | |
121 } | |
122 stream->allocated_rate_kbps = new_bitrate; | |
123 | |
124 return allocated_bitrate; | |
125 } | |
126 | |
127 void SimulcastState::RequestKeyFrame(uint8_t idx) { | |
128 RTC_DCHECK_LT(static_cast<size_t>(idx), streams_.size()); | |
129 streams_[idx].keyframe_request = true; | |
130 } | |
131 | |
132 bool SimulcastState::GetAndResetKeyFrameRequest(uint8_t idx) { | |
133 RTC_DCHECK_LT(static_cast<size_t>(idx), streams_.size()); | |
134 bool keyframe = streams_[idx].keyframe_request; | |
135 if (keyframe) | |
136 streams_[idx].keyframe_request = false; | |
137 return keyframe; | |
138 } | |
139 | |
140 std::vector<int> SimulcastState::GetStreamRates() const { | |
141 std::vector<int> rates; | |
142 for (const Stream& stream : streams_) | |
143 rates.push_back(stream.allocated_rate_kbps); | |
144 return rates; | |
145 } | |
146 | |
147 int SimulcastState::SumMaxBitrate() const { | |
148 return sum_max_bitrate_; | |
149 } | |
150 | |
151 int SimulcastState::SumTargetBitrate() const { | |
152 return sum_target_bitrate_; | |
153 } | |
154 | |
155 int SimulcastState::SumAllocatedBitrate() const { | |
pbos-webrtc
2016/04/29 21:23:27
Where do we actually need this?
| |
156 return sum_allocated_bitrate_; | |
157 } | |
158 | |
159 size_t SimulcastState::NumStreams() const { | |
160 return streams_.size(); | |
161 } | |
162 | |
163 size_t SimulcastState::NumSendingStreams() const { | |
164 size_t count = 0; | |
165 for (const Stream& stream : streams_) { | |
166 if (stream.sending) | |
167 ++count; | |
168 } | |
169 return count; | |
170 } | |
171 | |
172 bool SimulcastState::AnyKeyFrameRequested() const { | |
pbos-webrtc
2016/04/29 21:23:27
Is this used anywhere or should we just GetAndRese
| |
173 for (const Stream& stream : streams_) { | |
174 if (stream.keyframe_request) | |
175 return true; | |
176 } | |
177 return false; | |
178 } | |
179 | |
180 void SimulcastState::SetSending(uint8_t idx, bool sending) { | |
181 RTC_DCHECK(idx < streams_.size()); | |
182 if (sending && !streams_[idx].sending) | |
183 streams_[idx].keyframe_request = true; | |
184 streams_[idx].sending = sending; | |
185 } | |
186 | |
187 bool SimulcastState::IsSending(uint8_t idx) const { | |
188 RTC_DCHECK(idx < streams_.size()); | |
189 return streams_[idx].sending; | |
190 } | |
191 | |
192 int SimulcastState::AllocatedRate(uint8_t idx) const { | |
193 RTC_DCHECK(idx < streams_.size()); | |
194 return streams_[idx].allocated_rate_kbps; | |
195 } | |
196 | |
197 SimulcastState::Stream::Stream(uint8_t idx, VideoCodec* codec, int start_kbps) | |
198 : idx(idx), | |
199 config(codec->simulcastStream[idx]), | |
200 start_bitrate(std::max(static_cast<int>(config.minBitrate), start_kbps)), | |
201 parent_codec(codec), | |
202 sending(start_kbps >= start_bitrate), | |
203 keyframe_request(sending), | |
204 allocated_rate_kbps(start_bitrate) {} | |
205 | |
206 VideoCodec SimulcastState::Stream::AsCodec() const { | |
207 VideoCodec codec = *parent_codec; | |
208 codec.codecSpecific.VP8.numberOfTemporalLayers = | |
209 config.numberOfTemporalLayers; | |
210 codec.numberOfSimulcastStreams = 0; | |
211 codec.width = config.width; | |
212 codec.height = config.height; | |
213 codec.maxBitrate = config.maxBitrate; | |
214 codec.minBitrate = config.minBitrate; | |
215 codec.qpMax = config.qpMax; | |
216 codec.startBitrate = start_bitrate; | |
217 return codec; | |
218 } | |
219 | |
220 } // namespace webrtc | |
OLD | NEW |