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