| 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 #include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h" |  | 
| 12 |  | 
| 13 #include <algorithm> |  | 
| 14 #include <memory> |  | 
| 15 #include <vector> |  | 
| 16 #include <utility> |  | 
| 17 |  | 
| 18 #include "webrtc/base/checks.h" |  | 
| 19 |  | 
| 20 namespace webrtc { |  | 
| 21 |  | 
| 22 SimulcastRateAllocator::SimulcastRateAllocator( |  | 
| 23     const VideoCodec& codec, |  | 
| 24     std::unique_ptr<TemporalLayersFactory> tl_factory) |  | 
| 25     : codec_(codec), tl_factory_(std::move(tl_factory)) { |  | 
| 26   if (tl_factory_.get()) |  | 
| 27     tl_factory_->SetListener(this); |  | 
| 28 } |  | 
| 29 |  | 
| 30 void SimulcastRateAllocator::OnTemporalLayersCreated(int simulcast_id, |  | 
| 31                                                      TemporalLayers* layers) { |  | 
| 32   RTC_DCHECK(temporal_layers_.find(simulcast_id) == temporal_layers_.end()); |  | 
| 33   temporal_layers_[simulcast_id] = layers; |  | 
| 34 } |  | 
| 35 |  | 
| 36 BitrateAllocation SimulcastRateAllocator::GetAllocation( |  | 
| 37     uint32_t total_bitrate_bps, |  | 
| 38     uint32_t framerate) { |  | 
| 39   uint32_t left_to_allocate = total_bitrate_bps; |  | 
| 40   if (codec_.maxBitrate && codec_.maxBitrate * 1000 < left_to_allocate) |  | 
| 41     left_to_allocate = codec_.maxBitrate * 1000; |  | 
| 42 |  | 
| 43   BitrateAllocation allocated_bitrates_bps; |  | 
| 44   if (codec_.numberOfSimulcastStreams == 0) { |  | 
| 45     // No simulcast, just set the target as this has been capped already. |  | 
| 46     allocated_bitrates_bps.SetBitrate( |  | 
| 47         0, 0, std::max(codec_.minBitrate * 1000, left_to_allocate)); |  | 
| 48   } else { |  | 
| 49     // Always allocate enough bitrate for the minimum bitrate of the first |  | 
| 50     // layer. Suspending below min bitrate is controlled outside the codec |  | 
| 51     // implementation and is not overridden by this. |  | 
| 52     left_to_allocate = |  | 
| 53         std::max(codec_.simulcastStream[0].minBitrate * 1000, left_to_allocate); |  | 
| 54 |  | 
| 55     // Begin by allocating bitrate to simulcast streams, putting all bitrate in |  | 
| 56     // temporal layer 0. We'll then distribute this bitrate, across potential |  | 
| 57     // temporal layers, when stream allocation is done. |  | 
| 58 |  | 
| 59     // Allocate up to the target bitrate for each simulcast layer. |  | 
| 60     size_t layer = 0; |  | 
| 61     for (; layer < codec_.numberOfSimulcastStreams; ++layer) { |  | 
| 62       const SimulcastStream& stream = codec_.simulcastStream[layer]; |  | 
| 63       if (left_to_allocate < stream.minBitrate * 1000) |  | 
| 64         break; |  | 
| 65       uint32_t allocation = |  | 
| 66           std::min(left_to_allocate, stream.targetBitrate * 1000); |  | 
| 67       allocated_bitrates_bps.SetBitrate(layer, 0, allocation); |  | 
| 68       RTC_DCHECK_LE(allocation, left_to_allocate); |  | 
| 69       left_to_allocate -= allocation; |  | 
| 70     } |  | 
| 71 |  | 
| 72     // Next, try allocate remaining bitrate, up to max bitrate, in top stream. |  | 
| 73     // TODO(sprang): Allocate up to max bitrate for all layers once we have a |  | 
| 74     //               better idea of possible performance implications. |  | 
| 75     if (left_to_allocate > 0) { |  | 
| 76       size_t active_layer = layer - 1; |  | 
| 77       const SimulcastStream& stream = codec_.simulcastStream[active_layer]; |  | 
| 78       uint32_t bitrate_bps = |  | 
| 79           allocated_bitrates_bps.GetSpatialLayerSum(active_layer); |  | 
| 80       uint32_t allocation = |  | 
| 81           std::min(left_to_allocate, stream.maxBitrate * 1000 - bitrate_bps); |  | 
| 82       bitrate_bps += allocation; |  | 
| 83       RTC_DCHECK_LE(allocation, left_to_allocate); |  | 
| 84       left_to_allocate -= allocation; |  | 
| 85       allocated_bitrates_bps.SetBitrate(active_layer, 0, bitrate_bps); |  | 
| 86     } |  | 
| 87   } |  | 
| 88 |  | 
| 89   const int num_spatial_streams = |  | 
| 90       std::max(1, static_cast<int>(codec_.numberOfSimulcastStreams)); |  | 
| 91 |  | 
| 92   // Finally, distribute the bitrate for the simulcast streams across the |  | 
| 93   // available temporal layers. |  | 
| 94   for (int simulcast_id = 0; simulcast_id < num_spatial_streams; |  | 
| 95        ++simulcast_id) { |  | 
| 96     auto tl_it = temporal_layers_.find(simulcast_id); |  | 
| 97     if (tl_it == temporal_layers_.end()) |  | 
| 98       continue;  // TODO(sprang): If > 1 SS, assume default TL alloc? |  | 
| 99 |  | 
| 100     uint32_t target_bitrate_kbps = |  | 
| 101         allocated_bitrates_bps.GetBitrate(simulcast_id, 0) / 1000; |  | 
| 102     const uint32_t expected_allocated_bitrate_kbps = target_bitrate_kbps; |  | 
| 103     RTC_DCHECK_EQ( |  | 
| 104         target_bitrate_kbps, |  | 
| 105         allocated_bitrates_bps.GetSpatialLayerSum(simulcast_id) / 1000); |  | 
| 106     const int num_temporal_streams = std::max<uint8_t>( |  | 
| 107         1, codec_.numberOfSimulcastStreams == 0 |  | 
| 108                ? codec_.VP8().numberOfTemporalLayers |  | 
| 109                : codec_.simulcastStream[simulcast_id].numberOfTemporalLayers); |  | 
| 110 |  | 
| 111     uint32_t max_bitrate_kbps; |  | 
| 112     // Legacy temporal-layered only screenshare, or simulcast screenshare |  | 
| 113     // with legacy mode for simulcast stream 0. |  | 
| 114     if (codec_.mode == kScreensharing && codec_.targetBitrate > 0 && |  | 
| 115         ((num_spatial_streams == 1 && num_temporal_streams == 2) ||  // Legacy. |  | 
| 116          (num_spatial_streams > 1 && simulcast_id == 0))) {  // Simulcast. |  | 
| 117       // TODO(holmer): This is a "temporary" hack for screensharing, where we |  | 
| 118       // interpret the startBitrate as the encoder target bitrate. This is |  | 
| 119       // to allow for a different max bitrate, so if the codec can't meet |  | 
| 120       // the target we still allow it to overshoot up to the max before dropping |  | 
| 121       // frames. This hack should be improved. |  | 
| 122       int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate_kbps); |  | 
| 123       max_bitrate_kbps = std::min(codec_.maxBitrate, target_bitrate_kbps); |  | 
| 124       target_bitrate_kbps = tl0_bitrate; |  | 
| 125     } else if (num_spatial_streams == 1) { |  | 
| 126       max_bitrate_kbps = codec_.maxBitrate; |  | 
| 127     } else { |  | 
| 128       max_bitrate_kbps = codec_.simulcastStream[simulcast_id].maxBitrate; |  | 
| 129     } |  | 
| 130 |  | 
| 131     std::vector<uint32_t> tl_allocation = tl_it->second->OnRatesUpdated( |  | 
| 132         target_bitrate_kbps, max_bitrate_kbps, framerate); |  | 
| 133     RTC_DCHECK_GT(tl_allocation.size(), 0); |  | 
| 134     RTC_DCHECK_LE(tl_allocation.size(), num_temporal_streams); |  | 
| 135 |  | 
| 136     uint64_t tl_allocation_sum_kbps = 0; |  | 
| 137     for (size_t tl_index = 0; tl_index < tl_allocation.size(); ++tl_index) { |  | 
| 138       uint32_t layer_rate_kbps = tl_allocation[tl_index]; |  | 
| 139       allocated_bitrates_bps.SetBitrate(simulcast_id, tl_index, |  | 
| 140                                         layer_rate_kbps * 1000); |  | 
| 141       tl_allocation_sum_kbps += layer_rate_kbps; |  | 
| 142     } |  | 
| 143     RTC_DCHECK_LE(tl_allocation_sum_kbps, expected_allocated_bitrate_kbps); |  | 
| 144   } |  | 
| 145 |  | 
| 146   return allocated_bitrates_bps; |  | 
| 147 } |  | 
| 148 |  | 
| 149 uint32_t SimulcastRateAllocator::GetPreferredBitrateBps(uint32_t framerate) { |  | 
| 150   // Create a temporary instance without temporal layers, as they may be |  | 
| 151   // stateful, and updating the bitrate to max here can cause side effects. |  | 
| 152   SimulcastRateAllocator temp_allocator(codec_, nullptr); |  | 
| 153   BitrateAllocation allocation = |  | 
| 154       temp_allocator.GetAllocation(codec_.maxBitrate * 1000, framerate); |  | 
| 155   return allocation.get_sum_bps(); |  | 
| 156 } |  | 
| 157 |  | 
| 158 const VideoCodec& webrtc::SimulcastRateAllocator::GetCodec() const { |  | 
| 159   return codec_; |  | 
| 160 } |  | 
| 161 |  | 
| 162 }  // namespace webrtc |  | 
| OLD | NEW | 
|---|