OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 | 12 |
13 #include "webrtc/base/arraysize.h" | 13 #include "webrtc/base/arraysize.h" |
14 #include "webrtc/base/common.h" | 14 #include "webrtc/base/common.h" |
15 #include "webrtc/base/logging.h" | 15 #include "webrtc/base/logging.h" |
16 #include "webrtc/media/base/streamparams.h" | 16 #include "webrtc/media/base/streamparams.h" |
17 #include "webrtc/media/engine/constants.h" | |
18 #include "webrtc/media/engine/simulcast.h" | 17 #include "webrtc/media/engine/simulcast.h" |
19 #include "webrtc/system_wrappers/include/field_trial.h" | 18 #include "webrtc/system_wrappers/include/field_trial.h" |
20 | 19 |
21 namespace cricket { | 20 namespace cricket { |
22 | 21 |
23 struct SimulcastFormat { | 22 struct SimulcastFormat { |
24 int width; | 23 int width; |
25 int height; | 24 int height; |
26 // The maximum number of simulcast layers can be used for | 25 // The maximum number of simulcast layers can be used for |
27 // resolutions at |widthxheigh|. | 26 // resolutions at |widthxheigh|. |
(...skipping 15 matching lines...) Expand all Loading... |
43 const SimulcastFormat kSimulcastFormats[] = { | 42 const SimulcastFormat kSimulcastFormats[] = { |
44 {1920, 1080, 3, 5000, 4000, 800}, | 43 {1920, 1080, 3, 5000, 4000, 800}, |
45 {1280, 720, 3, 2500, 2500, 600}, | 44 {1280, 720, 3, 2500, 2500, 600}, |
46 {960, 540, 3, 900, 900, 450}, | 45 {960, 540, 3, 900, 900, 450}, |
47 {640, 360, 2, 700, 500, 150}, | 46 {640, 360, 2, 700, 500, 150}, |
48 {480, 270, 2, 450, 350, 150}, | 47 {480, 270, 2, 450, 350, 150}, |
49 {320, 180, 1, 200, 150, 30}, | 48 {320, 180, 1, 200, 150, 30}, |
50 {0, 0, 1, 200, 150, 30} | 49 {0, 0, 1, 200, 150, 30} |
51 }; | 50 }; |
52 | 51 |
53 const int kDefaultScreenshareSimulcastStreams = 2; | |
54 | |
55 // Multiway: Number of temporal layers for each simulcast stream, for maximum | 52 // Multiway: Number of temporal layers for each simulcast stream, for maximum |
56 // possible number of simulcast streams |kMaxSimulcastStreams|. The array | 53 // possible number of simulcast streams |kMaxSimulcastStreams|. The array |
57 // goes from lowest resolution at position 0 to highest resolution. | 54 // goes from lowest resolution at position 0 to highest resolution. |
58 // For example, first three elements correspond to say: QVGA, VGA, WHD. | 55 // For example, first three elements correspond to say: QVGA, VGA, WHD. |
59 static const int | 56 static const int |
60 kDefaultConferenceNumberOfTemporalLayers[webrtc::kMaxSimulcastStreams] = | 57 kDefaultConferenceNumberOfTemporalLayers[webrtc::kMaxSimulcastStreams] = |
61 {3, 3, 3, 3}; | 58 {3, 3, 3, 3}; |
62 | 59 |
63 void GetSimulcastSsrcs(const StreamParams& sp, std::vector<uint32_t>* ssrcs) { | 60 void GetSimulcastSsrcs(const StreamParams& sp, std::vector<uint32_t>* ssrcs) { |
64 const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics); | 61 const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics); |
(...skipping 10 matching lines...) Expand all Loading... |
75 int temp = *width; | 72 int temp = *width; |
76 *width = *height; | 73 *width = *height; |
77 *height = temp; | 74 *height = temp; |
78 } | 75 } |
79 } | 76 } |
80 | 77 |
81 int FindSimulcastFormatIndex(int width, int height) { | 78 int FindSimulcastFormatIndex(int width, int height) { |
82 MaybeExchangeWidthHeight(&width, &height); | 79 MaybeExchangeWidthHeight(&width, &height); |
83 | 80 |
84 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) { | 81 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) { |
85 if (width * height >= | 82 if (width >= kSimulcastFormats[i].width && |
86 kSimulcastFormats[i].width * kSimulcastFormats[i].height) { | 83 height >= kSimulcastFormats[i].height) { |
87 return i; | 84 return i; |
88 } | 85 } |
89 } | 86 } |
90 return -1; | 87 return -1; |
91 } | 88 } |
92 | 89 |
93 int FindSimulcastFormatIndex(int width, int height, size_t max_layers) { | 90 int FindSimulcastFormatIndex(int width, int height, size_t max_layers) { |
94 MaybeExchangeWidthHeight(&width, &height); | 91 MaybeExchangeWidthHeight(&width, &height); |
95 | 92 |
96 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) { | 93 for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) { |
97 if (width * height >= | 94 if (width >= kSimulcastFormats[i].width && |
98 kSimulcastFormats[i].width * kSimulcastFormats[i].height && | 95 height >= kSimulcastFormats[i].height && |
99 max_layers == kSimulcastFormats[i].max_layers) { | 96 max_layers == kSimulcastFormats[i].max_layers) { |
100 return i; | 97 return i; |
101 } | 98 } |
102 } | 99 } |
103 return -1; | 100 return -1; |
104 } | 101 } |
105 | 102 |
106 // Simulcast stream width and height must both be dividable by | 103 // Simulcast stream width and height must both be dividable by |
107 // |2 ^ simulcast_layers - 1|. | 104 // |2 ^ simulcast_layers - 1|. |
108 int NormalizeSimulcastSize(int size, size_t simulcast_layers) { | 105 int NormalizeSimulcastSize(int size, size_t simulcast_layers) { |
109 const int base2_exponent = static_cast<int>(simulcast_layers) - 1; | 106 const int base2_exponent = static_cast<int>(simulcast_layers) - 1; |
110 return ((size >> base2_exponent) << base2_exponent); | 107 return ((size >> base2_exponent) << base2_exponent); |
111 } | 108 } |
112 | 109 |
113 size_t FindSimulcastMaxLayers(int width, int height) { | 110 size_t FindSimulcastMaxLayers(int width, int height) { |
114 int index = FindSimulcastFormatIndex(width, height); | 111 int index = FindSimulcastFormatIndex(width, height); |
115 if (index == -1) { | 112 if (index == -1) { |
116 return -1; | 113 return -1; |
117 } | 114 } |
118 return kSimulcastFormats[index].max_layers; | 115 return kSimulcastFormats[index].max_layers; |
119 } | 116 } |
120 | 117 |
121 // TODO(marpan): Investigate if we should return 0 instead of -1 in | 118 // TODO(marpan): Investigate if we should return 0 instead of -1 in |
122 // FindSimulcast[Max/Target/Min]Bitrate functions below, since the | 119 // FindSimulcast[Max/Target/Min]Bitrate functions below, since the |
123 // codec struct max/min/targeBitrates are unsigned. | 120 // codec struct max/min/targeBitrates are unsigned. |
124 int FindSimulcastMaxBitrateBps(int width, int height) { | 121 int FindSimulcastMaxBitrateBps(int width, int height, size_t max_layers) { |
125 const int format_index = FindSimulcastFormatIndex(width, height); | 122 const int format_index = FindSimulcastFormatIndex(width, height); |
126 if (format_index == -1) { | 123 if (format_index == -1) { |
127 return -1; | 124 return -1; |
128 } | 125 } |
129 return kSimulcastFormats[format_index].max_bitrate_kbps * 1000; | 126 return kSimulcastFormats[format_index].max_bitrate_kbps * 1000; |
130 } | 127 } |
131 | 128 |
132 int FindSimulcastTargetBitrateBps(int width, int height) { | 129 int FindSimulcastTargetBitrateBps(int width, |
| 130 int height, |
| 131 size_t max_layers) { |
133 const int format_index = FindSimulcastFormatIndex(width, height); | 132 const int format_index = FindSimulcastFormatIndex(width, height); |
134 if (format_index == -1) { | 133 if (format_index == -1) { |
135 return -1; | 134 return -1; |
136 } | 135 } |
137 return kSimulcastFormats[format_index].target_bitrate_kbps * 1000; | 136 return kSimulcastFormats[format_index].target_bitrate_kbps * 1000; |
138 } | 137 } |
139 | 138 |
140 int FindSimulcastMinBitrateBps(int width, int height) { | 139 int FindSimulcastMinBitrateBps(int width, int height, size_t max_layers) { |
141 const int format_index = FindSimulcastFormatIndex(width, height); | 140 const int format_index = FindSimulcastFormatIndex(width, height); |
142 if (format_index == -1) { | 141 if (format_index == -1) { |
143 return -1; | 142 return -1; |
144 } | 143 } |
145 return kSimulcastFormats[format_index].min_bitrate_kbps * 1000; | 144 return kSimulcastFormats[format_index].min_bitrate_kbps * 1000; |
146 } | 145 } |
147 | 146 |
148 bool SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) { | 147 bool SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) { |
149 int index = FindSimulcastFormatIndex(*width, *height, max_layers); | 148 int index = FindSimulcastFormatIndex(*width, *height, max_layers); |
150 if (index == -1) { | 149 if (index == -1) { |
(...skipping 10 matching lines...) Expand all Loading... |
161 | 160 |
162 int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& streams) { | 161 int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& streams) { |
163 int total_max_bitrate_bps = 0; | 162 int total_max_bitrate_bps = 0; |
164 for (size_t s = 0; s < streams.size() - 1; ++s) { | 163 for (size_t s = 0; s < streams.size() - 1; ++s) { |
165 total_max_bitrate_bps += streams[s].target_bitrate_bps; | 164 total_max_bitrate_bps += streams[s].target_bitrate_bps; |
166 } | 165 } |
167 total_max_bitrate_bps += streams.back().max_bitrate_bps; | 166 total_max_bitrate_bps += streams.back().max_bitrate_bps; |
168 return total_max_bitrate_bps; | 167 return total_max_bitrate_bps; |
169 } | 168 } |
170 | 169 |
171 std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_streams, | 170 std::vector<webrtc::VideoStream> GetSimulcastConfig( |
172 int width, | 171 size_t max_streams, |
173 int height, | 172 int width, |
174 int max_bitrate_bps, | 173 int height, |
175 int max_qp, | 174 int max_bitrate_bps, |
176 int max_framerate, | 175 int max_qp, |
177 bool is_screencast) { | 176 int max_framerate) { |
178 size_t num_simulcast_layers; | 177 size_t simulcast_layers = FindSimulcastMaxLayers(width, height); |
179 if (is_screencast) { | 178 if (simulcast_layers > max_streams) { |
180 num_simulcast_layers = | |
181 UseSimulcastScreenshare() ? kDefaultScreenshareSimulcastStreams : 1; | |
182 } else { | |
183 num_simulcast_layers = FindSimulcastMaxLayers(width, height); | |
184 } | |
185 | |
186 if (num_simulcast_layers > max_streams) { | |
187 // If the number of SSRCs in the group differs from our target | 179 // If the number of SSRCs in the group differs from our target |
188 // number of simulcast streams for current resolution, switch down | 180 // number of simulcast streams for current resolution, switch down |
189 // to a resolution that matches our number of SSRCs. | 181 // to a resolution that matches our number of SSRCs. |
190 if (!SlotSimulcastMaxResolution(max_streams, &width, &height)) { | 182 if (!SlotSimulcastMaxResolution(max_streams, &width, &height)) { |
191 return std::vector<webrtc::VideoStream>(); | 183 return std::vector<webrtc::VideoStream>(); |
192 } | 184 } |
193 num_simulcast_layers = max_streams; | 185 simulcast_layers = max_streams; |
194 } | 186 } |
195 std::vector<webrtc::VideoStream> streams; | 187 std::vector<webrtc::VideoStream> streams; |
196 streams.resize(num_simulcast_layers); | 188 streams.resize(simulcast_layers); |
197 | 189 |
198 if (!is_screencast) { | 190 // Format width and height has to be divisible by |2 ^ number_streams - 1|. |
199 // Format width and height has to be divisible by |2 ^ number_streams - 1|. | 191 width = NormalizeSimulcastSize(width, simulcast_layers); |
200 width = NormalizeSimulcastSize(width, num_simulcast_layers); | 192 height = NormalizeSimulcastSize(height, simulcast_layers); |
201 height = NormalizeSimulcastSize(height, num_simulcast_layers); | |
202 } | |
203 | 193 |
204 // Add simulcast sub-streams from lower resolution to higher resolutions. | 194 // Add simulcast sub-streams from lower resolution to higher resolutions. |
205 // Add simulcast streams, from highest resolution (|s| = number_streams -1) | 195 // Add simulcast streams, from highest resolution (|s| = number_streams -1) |
206 // to lowest resolution at |s| = 0. | 196 // to lowest resolution at |s| = 0. |
207 for (size_t s = num_simulcast_layers - 1;; --s) { | 197 for (size_t s = simulcast_layers - 1;; --s) { |
208 streams[s].width = width; | 198 streams[s].width = width; |
209 streams[s].height = height; | 199 streams[s].height = height; |
210 // TODO(pbos): Fill actual temporal-layer bitrate thresholds. | 200 // TODO(pbos): Fill actual temporal-layer bitrate thresholds. |
| 201 streams[s].temporal_layer_thresholds_bps.resize( |
| 202 kDefaultConferenceNumberOfTemporalLayers[s] - 1); |
| 203 streams[s].max_bitrate_bps = |
| 204 FindSimulcastMaxBitrateBps(width, height, simulcast_layers); |
| 205 streams[s].target_bitrate_bps = |
| 206 FindSimulcastTargetBitrateBps(width, height, simulcast_layers); |
| 207 streams[s].min_bitrate_bps = |
| 208 FindSimulcastMinBitrateBps(width, height, simulcast_layers); |
211 streams[s].max_qp = max_qp; | 209 streams[s].max_qp = max_qp; |
212 if (is_screencast && s == 0) { | 210 streams[s].max_framerate = max_framerate; |
213 ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault(); | |
214 // For legacy screenshare in conference mode, tl0 and tl1 bitrates are | |
215 // piggybacked on the VideoCodec struct as target and max bitrates, | |
216 // respectively. See eg. webrtc::VP8EncoderImpl::SetRates(). | |
217 streams[s].min_bitrate_bps = kMinVideoBitrateKbps * 1000; | |
218 streams[s].target_bitrate_bps = config.tl0_bitrate_kbps * 1000; | |
219 streams[s].max_bitrate_bps = config.tl1_bitrate_kbps * 1000; | |
220 streams[s].temporal_layer_thresholds_bps.clear(); | |
221 streams[s].temporal_layer_thresholds_bps.push_back( | |
222 config.tl0_bitrate_kbps * 1000); | |
223 streams[s].max_framerate = 5; | |
224 } else { | |
225 streams[s].temporal_layer_thresholds_bps.resize( | |
226 kDefaultConferenceNumberOfTemporalLayers[s] - 1); | |
227 streams[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height); | |
228 streams[s].target_bitrate_bps = | |
229 FindSimulcastTargetBitrateBps(width, height); | |
230 streams[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height); | |
231 streams[s].max_framerate = max_framerate; | |
232 } | |
233 | |
234 width /= 2; | 211 width /= 2; |
235 height /= 2; | 212 height /= 2; |
236 if (s == 0) | 213 if (s == 0) { |
237 break; | 214 break; |
| 215 } |
238 } | 216 } |
239 | 217 |
240 // Spend additional bits to boost the max stream. | 218 // Spend additional bits to boost the max stream. |
241 int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(streams); | 219 int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(streams); |
242 if (bitrate_left_bps > 0) { | 220 if (bitrate_left_bps > 0) { |
243 streams.back().max_bitrate_bps += bitrate_left_bps; | 221 streams.back().max_bitrate_bps += bitrate_left_bps; |
244 } | 222 } |
245 | 223 |
246 return streams; | 224 return streams; |
247 } | 225 } |
248 | 226 |
249 static const int kScreenshareMinBitrateKbps = 50; | 227 static const int kScreenshareMinBitrateKbps = 50; |
250 static const int kScreenshareMaxBitrateKbps = 6000; | 228 static const int kScreenshareMaxBitrateKbps = 6000; |
251 static const int kScreenshareDefaultTl0BitrateKbps = 200; | 229 static const int kScreenshareDefaultTl0BitrateKbps = 200; |
252 static const int kScreenshareDefaultTl1BitrateKbps = 1000; | 230 static const int kScreenshareDefaultTl1BitrateKbps = 1000; |
253 | 231 |
254 static const char* kScreencastLayerFieldTrialName = | 232 static const char* kScreencastLayerFieldTrialName = |
255 "WebRTC-ScreenshareLayerRates"; | 233 "WebRTC-ScreenshareLayerRates"; |
256 static const char* kSimulcastScreenshareFieldTrialName = | |
257 "WebRTC-SimulcastScreenshare"; | |
258 | 234 |
259 ScreenshareLayerConfig::ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate) | 235 ScreenshareLayerConfig::ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate) |
260 : tl0_bitrate_kbps(tl0_bitrate), tl1_bitrate_kbps(tl1_bitrate) { | 236 : tl0_bitrate_kbps(tl0_bitrate), tl1_bitrate_kbps(tl1_bitrate) { |
261 } | 237 } |
262 | 238 |
263 ScreenshareLayerConfig ScreenshareLayerConfig::GetDefault() { | 239 ScreenshareLayerConfig ScreenshareLayerConfig::GetDefault() { |
264 std::string group = | 240 std::string group = |
265 webrtc::field_trial::FindFullName(kScreencastLayerFieldTrialName); | 241 webrtc::field_trial::FindFullName(kScreencastLayerFieldTrialName); |
266 | 242 |
267 ScreenshareLayerConfig config(kScreenshareDefaultTl0BitrateKbps, | 243 ScreenshareLayerConfig config(kScreenshareDefaultTl0BitrateKbps, |
(...skipping 22 matching lines...) Expand all Loading... |
290 tl1_bitrate > kScreenshareMaxBitrateKbps || tl0_bitrate > tl1_bitrate) { | 266 tl1_bitrate > kScreenshareMaxBitrateKbps || tl0_bitrate > tl1_bitrate) { |
291 return false; | 267 return false; |
292 } | 268 } |
293 | 269 |
294 config->tl0_bitrate_kbps = tl0_bitrate; | 270 config->tl0_bitrate_kbps = tl0_bitrate; |
295 config->tl1_bitrate_kbps = tl1_bitrate; | 271 config->tl1_bitrate_kbps = tl1_bitrate; |
296 | 272 |
297 return true; | 273 return true; |
298 } | 274 } |
299 | 275 |
300 bool UseSimulcastScreenshare() { | |
301 return webrtc::field_trial::FindFullName( | |
302 kSimulcastScreenshareFieldTrialName) == "Enabled"; | |
303 } | |
304 | |
305 } // namespace cricket | 276 } // namespace cricket |
OLD | NEW |