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