pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 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 | */ |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 10 | #include "video/video_send_stream.h" |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 | [diff] [blame] | 11 | |
perkj | 71ee44c | 2016-06-15 07:47:53 | [diff] [blame] | 12 | #include <utility> |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 | [diff] [blame] | 13 | |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 14 | #include "api/array_view.h" |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 15 | #include "api/video/video_stream_encoder_settings.h" |
| 16 | #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" |
Danil Chapovalov | 7b18992 | 2018-10-03 08:15:36 | [diff] [blame] | 17 | #include "modules/rtp_rtcp/source/rtp_header_extension_size.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 18 | #include "modules/rtp_rtcp/source/rtp_sender.h" |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 19 | #include "rtc_base/checks.h" |
Stefan Holmer | dbdb3a0 | 2018-07-17 14:03:46 | [diff] [blame] | 20 | #include "rtc_base/logging.h" |
Rasmus Brandt | 9731a14 | 2020-02-26 14:42:19 | [diff] [blame] | 21 | #include "rtc_base/strings/string_builder.h" |
Danil Chapovalov | 1aa7581 | 2019-03-05 10:11:35 | [diff] [blame] | 22 | #include "rtc_base/task_utils/to_queued_task.h" |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 23 | #include "system_wrappers/include/clock.h" |
Rasmus Brandt | bdc6c40 | 2018-11-06 11:55:53 | [diff] [blame] | 24 | #include "system_wrappers/include/field_trial.h" |
Per Kjellander | b03b6c8 | 2021-01-03 09:26:03 | [diff] [blame] | 25 | #include "video/adaptation/overuse_frame_detector.h" |
Sebastian Jansson | 8e0b15b | 2018-04-18 17:19:22 | [diff] [blame] | 26 | #include "video/video_send_stream_impl.h" |
Per Kjellander | b03b6c8 | 2021-01-03 09:26:03 | [diff] [blame] | 27 | #include "video/video_stream_encoder.h" |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 | [diff] [blame] | 28 | |
| 29 | namespace webrtc { |
mflodman | 949c2f0 | 2015-10-16 09:31:11 | [diff] [blame] | 30 | |
Per | 83d0910 | 2016-04-15 12:59:13 | [diff] [blame] | 31 | namespace { |
| 32 | |
Stefan Holmer | dbdb3a0 | 2018-07-17 14:03:46 | [diff] [blame] | 33 | size_t CalculateMaxHeaderSize(const RtpConfig& config) { |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 14:46:17 | [diff] [blame] | 34 | size_t header_size = kRtpHeaderSize; |
| 35 | size_t extensions_size = 0; |
| 36 | size_t fec_extensions_size = 0; |
Benjamin Wright | 1f4173e | 2019-03-14 00:59:32 | [diff] [blame] | 37 | if (!config.extensions.empty()) { |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 14:46:17 | [diff] [blame] | 38 | RtpHeaderExtensionMap extensions_map(config.extensions); |
Danil Chapovalov | 7b18992 | 2018-10-03 08:15:36 | [diff] [blame] | 39 | extensions_size = RtpHeaderExtensionSize(RTPSender::VideoExtensionSizes(), |
| 40 | extensions_map); |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 14:46:17 | [diff] [blame] | 41 | fec_extensions_size = |
Danil Chapovalov | 7b18992 | 2018-10-03 08:15:36 | [diff] [blame] | 42 | RtpHeaderExtensionSize(RTPSender::FecExtensionSizes(), extensions_map); |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 14:46:17 | [diff] [blame] | 43 | } |
| 44 | header_size += extensions_size; |
| 45 | if (config.flexfec.payload_type >= 0) { |
| 46 | // All FEC extensions again plus maximum FlexFec overhead. |
| 47 | header_size += fec_extensions_size + 32; |
| 48 | } else { |
| 49 | if (config.ulpfec.ulpfec_payload_type >= 0) { |
| 50 | // Header with all the FEC extensions will be repeated plus maximum |
| 51 | // UlpFec overhead. |
| 52 | header_size += fec_extensions_size + 18; |
| 53 | } |
| 54 | if (config.ulpfec.red_payload_type >= 0) { |
| 55 | header_size += 1; // RED header. |
| 56 | } |
| 57 | } |
| 58 | // Additional room for Rtx. |
| 59 | if (config.rtx.payload_type >= 0) |
| 60 | header_size += kRtxHeaderSize; |
| 61 | return header_size; |
| 62 | } |
| 63 | |
Per Kjellander | b03b6c8 | 2021-01-03 09:26:03 | [diff] [blame] | 64 | VideoStreamEncoder::BitrateAllocationCallbackType |
| 65 | GetBitrateAllocationCallbackType(const VideoSendStream::Config& config) { |
| 66 | if (webrtc::RtpExtension::FindHeaderExtensionByUri( |
| 67 | config.rtp.extensions, |
| 68 | webrtc::RtpExtension::kVideoLayersAllocationUri)) { |
| 69 | return VideoStreamEncoder::BitrateAllocationCallbackType:: |
| 70 | kVideoLayersAllocation; |
| 71 | } |
| 72 | if (field_trial::IsEnabled("WebRTC-Target-Bitrate-Rtcp")) { |
| 73 | return VideoStreamEncoder::BitrateAllocationCallbackType:: |
| 74 | kVideoBitrateAllocation; |
| 75 | } |
| 76 | return VideoStreamEncoder::BitrateAllocationCallbackType:: |
| 77 | kVideoBitrateAllocationWhenScreenSharing; |
| 78 | } |
| 79 | |
Peter Boström | e449915 | 2016-02-05 10:13:28 | [diff] [blame] | 80 | } // namespace |
| 81 | |
pbos@webrtc.org | 024e4d5 | 2014-05-15 10:03:24 | [diff] [blame] | 82 | namespace internal { |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 83 | |
pbos@webrtc.org | 2bb1bda | 2014-07-07 13:06:48 | [diff] [blame] | 84 | VideoSendStream::VideoSendStream( |
Sebastian Jansson | 572c60f | 2019-03-04 17:30:41 | [diff] [blame] | 85 | Clock* clock, |
Peter Boström | 45553ae | 2015-05-08 11:54:38 | [diff] [blame] | 86 | int num_cpu_cores, |
Peter Boström | f16fcbe | 2015-04-30 10:16:05 | [diff] [blame] | 87 | ProcessThread* module_process_thread, |
Sebastian Jansson | 74682c1 | 2019-03-01 10:50:20 | [diff] [blame] | 88 | TaskQueueFactory* task_queue_factory, |
Tommi | 8ae18ad | 2020-05-03 20:45:02 | [diff] [blame] | 89 | RtcpRttStats* call_stats, |
nisse | b8f9a32 | 2017-03-27 12:36:15 | [diff] [blame] | 90 | RtpTransportControllerSendInterface* transport, |
Niels Möller | 67b011d | 2018-10-22 11:00:40 | [diff] [blame] | 91 | BitrateAllocatorInterface* bitrate_allocator, |
asapersson | 35151f3 | 2016-05-03 06:44:01 | [diff] [blame] | 92 | SendDelayStats* send_delay_stats, |
terelius | adafe0b | 2016-05-26 08:58:40 | [diff] [blame] | 93 | RtcEventLog* event_log, |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 94 | VideoSendStream::Config config, |
| 95 | VideoEncoderConfig encoder_config, |
Åsa Persson | 4bece9a | 2017-10-06 08:04:04 | [diff] [blame] | 96 | const std::map<uint32_t, RtpState>& suspended_ssrcs, |
Ying Wang | 3b790f3 | 2018-01-19 16:58:57 | [diff] [blame] | 97 | const std::map<uint32_t, RtpPayloadState>& suspended_payload_states, |
Stefan Holmer | dbdb3a0 | 2018-07-17 14:03:46 | [diff] [blame] | 98 | std::unique_ptr<FecController> fec_controller) |
Sebastian Jansson | 0b69826 | 2019-03-07 08:17:19 | [diff] [blame] | 99 | : worker_queue_(transport->GetWorkerQueue()), |
Sebastian Jansson | 572c60f | 2019-03-04 17:30:41 | [diff] [blame] | 100 | stats_proxy_(clock, config, encoder_config.content_type), |
sprang | f24a064 | 2017-02-28 21:23:26 | [diff] [blame] | 101 | config_(std::move(config)), |
| 102 | content_type_(encoder_config.content_type) { |
Niels Möller | 4db138e | 2018-04-19 07:04:13 | [diff] [blame] | 103 | RTC_DCHECK(config_.encoder_settings.encoder_factory); |
Jiawei Ou | c2ebe21 | 2018-11-08 18:02:56 | [diff] [blame] | 104 | RTC_DCHECK(config_.encoder_settings.bitrate_allocator_factory); |
Niels Möller | 4db138e | 2018-04-19 07:04:13 | [diff] [blame] | 105 | |
Per Kjellander | b03b6c8 | 2021-01-03 09:26:03 | [diff] [blame] | 106 | video_stream_encoder_ = std::make_unique<VideoStreamEncoder>( |
| 107 | clock, num_cpu_cores, &stats_proxy_, config_.encoder_settings, |
| 108 | std::make_unique<OveruseFrameDetector>(&stats_proxy_), task_queue_factory, |
| 109 | GetBitrateAllocationCallbackType(config_)); |
| 110 | |
Sebastian Jansson | 06b83aa | 2018-02-28 12:03:46 | [diff] [blame] | 111 | // TODO(srte): Initialization should not be done posted on a task queue. |
| 112 | // Note that the posted task must not outlive this scope since the closure |
| 113 | // references local variables. |
Danil Chapovalov | 1aa7581 | 2019-03-05 10:11:35 | [diff] [blame] | 114 | worker_queue_->PostTask(ToQueuedTask( |
Sebastian Jansson | 572c60f | 2019-03-04 17:30:41 | [diff] [blame] | 115 | [this, clock, call_stats, transport, bitrate_allocator, send_delay_stats, |
Sebastian Jansson | 06b83aa | 2018-02-28 12:03:46 | [diff] [blame] | 116 | event_log, &suspended_ssrcs, &encoder_config, &suspended_payload_states, |
Stefan Holmer | dbdb3a0 | 2018-07-17 14:03:46 | [diff] [blame] | 117 | &fec_controller]() { |
Sebastian Jansson | 06b83aa | 2018-02-28 12:03:46 | [diff] [blame] | 118 | send_stream_.reset(new VideoSendStreamImpl( |
Sebastian Jansson | 572c60f | 2019-03-04 17:30:41 | [diff] [blame] | 119 | clock, &stats_proxy_, worker_queue_, call_stats, transport, |
Sebastian Jansson | 06b83aa | 2018-02-28 12:03:46 | [diff] [blame] | 120 | bitrate_allocator, send_delay_stats, video_stream_encoder_.get(), |
| 121 | event_log, &config_, encoder_config.max_bitrate_bps, |
| 122 | encoder_config.bitrate_priority, suspended_ssrcs, |
| 123 | suspended_payload_states, encoder_config.content_type, |
Bjorn A Mellem | 7a9a092 | 2019-11-26 17:19:40 | [diff] [blame] | 124 | std::move(fec_controller))); |
Sebastian Jansson | 06b83aa | 2018-02-28 12:03:46 | [diff] [blame] | 125 | }, |
| 126 | [this]() { thread_sync_event_.Set(); })); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 127 | |
| 128 | // Wait for ConstructionTask to complete so that |send_stream_| can be used. |
| 129 | // |module_process_thread| must be registered and deregistered on the thread |
| 130 | // it was created on. |
| 131 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 132 | send_stream_->RegisterProcessThread(module_process_thread); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 133 | ReconfigureVideoEncoder(std::move(encoder_config)); |
| 134 | } |
| 135 | |
| 136 | VideoSendStream::~VideoSendStream() { |
| 137 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 138 | RTC_DCHECK(!send_stream_); |
| 139 | } |
| 140 | |
Seth Hampson | cc7125f | 2018-02-02 16:46:16 | [diff] [blame] | 141 | void VideoSendStream::UpdateActiveSimulcastLayers( |
| 142 | const std::vector<bool> active_layers) { |
| 143 | RTC_DCHECK_RUN_ON(&thread_checker_); |
Rasmus Brandt | 9731a14 | 2020-02-26 14:42:19 | [diff] [blame] | 144 | |
| 145 | rtc::StringBuilder active_layers_string; |
| 146 | active_layers_string << "{"; |
| 147 | for (size_t i = 0; i < active_layers.size(); ++i) { |
| 148 | if (active_layers[i]) { |
| 149 | active_layers_string << "1"; |
| 150 | } else { |
| 151 | active_layers_string << "0"; |
| 152 | } |
| 153 | if (i < active_layers.size() - 1) { |
| 154 | active_layers_string << ", "; |
| 155 | } |
| 156 | } |
| 157 | active_layers_string << "}"; |
| 158 | RTC_LOG(LS_INFO) << "UpdateActiveSimulcastLayers: " |
| 159 | << active_layers_string.str(); |
| 160 | |
Seth Hampson | cc7125f | 2018-02-02 16:46:16 | [diff] [blame] | 161 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 162 | worker_queue_->PostTask([this, send_stream, active_layers] { |
| 163 | send_stream->UpdateActiveSimulcastLayers(active_layers); |
| 164 | thread_sync_event_.Set(); |
| 165 | }); |
| 166 | |
| 167 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 168 | } |
| 169 | |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 170 | void VideoSendStream::Start() { |
| 171 | RTC_DCHECK_RUN_ON(&thread_checker_); |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 172 | RTC_LOG(LS_INFO) << "VideoSendStream::Start"; |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 173 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 174 | worker_queue_->PostTask([this, send_stream] { |
| 175 | send_stream->Start(); |
| 176 | thread_sync_event_.Set(); |
| 177 | }); |
| 178 | |
| 179 | // It is expected that after VideoSendStream::Start has been called, incoming |
mflodman | cc3d442 | 2017-08-03 15:27:51 | [diff] [blame] | 180 | // frames are not dropped in VideoStreamEncoder. To ensure this, Start has to |
| 181 | // be synchronized. |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 182 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 183 | } |
| 184 | |
| 185 | void VideoSendStream::Stop() { |
| 186 | RTC_DCHECK_RUN_ON(&thread_checker_); |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 187 | RTC_LOG(LS_INFO) << "VideoSendStream::Stop"; |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 188 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 189 | worker_queue_->PostTask([send_stream] { send_stream->Stop(); }); |
| 190 | } |
| 191 | |
Henrik Boström | f4a9991 | 2020-06-11 10:07:14 | [diff] [blame] | 192 | void VideoSendStream::AddAdaptationResource( |
| 193 | rtc::scoped_refptr<Resource> resource) { |
| 194 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 195 | video_stream_encoder_->AddAdaptationResource(resource); |
| 196 | } |
| 197 | |
| 198 | std::vector<rtc::scoped_refptr<Resource>> |
| 199 | VideoSendStream::GetAdaptationResources() { |
| 200 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 201 | return video_stream_encoder_->GetAdaptationResources(); |
| 202 | } |
| 203 | |
perkj | a49cbd3 | 2016-09-16 14:53:41 | [diff] [blame] | 204 | void VideoSendStream::SetSource( |
perkj | 803d97f | 2016-11-01 18:45:46 | [diff] [blame] | 205 | rtc::VideoSourceInterface<webrtc::VideoFrame>* source, |
| 206 | const DegradationPreference& degradation_preference) { |
perkj | a49cbd3 | 2016-09-16 14:53:41 | [diff] [blame] | 207 | RTC_DCHECK_RUN_ON(&thread_checker_); |
mflodman | cc3d442 | 2017-08-03 15:27:51 | [diff] [blame] | 208 | video_stream_encoder_->SetSource(source, degradation_preference); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 209 | } |
| 210 | |
| 211 | void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) { |
perkj | fa10b55 | 2016-10-03 06:45:26 | [diff] [blame] | 212 | // TODO(perkj): Some test cases in VideoSendStreamTest call |
| 213 | // ReconfigureVideoEncoder from the network thread. |
| 214 | // RTC_DCHECK_RUN_ON(&thread_checker_); |
sprang | f24a064 | 2017-02-28 21:23:26 | [diff] [blame] | 215 | RTC_DCHECK(content_type_ == config.content_type); |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 14:46:17 | [diff] [blame] | 216 | video_stream_encoder_->ConfigureEncoder( |
| 217 | std::move(config), |
Niels Möller | f133856 | 2018-04-26 07:51:47 | [diff] [blame] | 218 | config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp)); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | VideoSendStream::Stats VideoSendStream::GetStats() { |
| 222 | // TODO(perkj, solenberg): Some test cases in EndToEndTest call GetStats from |
| 223 | // a network thread. See comment in Call::GetStats(). |
| 224 | // RTC_DCHECK_RUN_ON(&thread_checker_); |
| 225 | return stats_proxy_.GetStats(); |
| 226 | } |
| 227 | |
Danil Chapovalov | b9b146c | 2018-06-15 10:28:07 | [diff] [blame] | 228 | absl::optional<float> VideoSendStream::GetPacingFactorOverride() const { |
Sebastian Jansson | a45c8da | 2018-01-16 09:55:29 | [diff] [blame] | 229 | return send_stream_->configured_pacing_factor_; |
| 230 | } |
| 231 | |
Åsa Persson | 4bece9a | 2017-10-06 08:04:04 | [diff] [blame] | 232 | void VideoSendStream::StopPermanentlyAndGetRtpStates( |
| 233 | VideoSendStream::RtpStateMap* rtp_state_map, |
| 234 | VideoSendStream::RtpPayloadStateMap* payload_state_map) { |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 235 | RTC_DCHECK_RUN_ON(&thread_checker_); |
mflodman | cc3d442 | 2017-08-03 15:27:51 | [diff] [blame] | 236 | video_stream_encoder_->Stop(); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 237 | send_stream_->DeRegisterProcessThread(); |
Sebastian Jansson | 1b2e90b | 2018-03-05 18:09:11 | [diff] [blame] | 238 | worker_queue_->PostTask([this, rtp_state_map, payload_state_map]() { |
| 239 | send_stream_->Stop(); |
| 240 | *rtp_state_map = send_stream_->GetRtpStates(); |
| 241 | *payload_state_map = send_stream_->GetRtpPayloadStates(); |
| 242 | send_stream_.reset(); |
| 243 | thread_sync_event_.Set(); |
| 244 | }); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 245 | thread_sync_event_.Wait(rtc::Event::kForever); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 246 | } |
| 247 | |
Niels Möller | 8fb1a6a | 2019-03-05 13:29:42 | [diff] [blame] | 248 | void VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 249 | // Called on a network thread. |
Niels Möller | 8fb1a6a | 2019-03-05 13:29:42 | [diff] [blame] | 250 | send_stream_->DeliverRtcp(packet, length); |
perkj | 26091b1 | 2016-09-01 08:17:40 | [diff] [blame] | 251 | } |
| 252 | |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 | [diff] [blame] | 253 | } // namespace internal |
| 254 | } // namespace webrtc |