pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 +0000 | [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 06:47:31 +0200 | [diff] [blame] | 10 | #include "video/video_send_stream.h" |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 +0000 | [diff] [blame] | 11 | |
perkj | 71ee44c | 2016-06-15 00:47:53 -0700 | [diff] [blame] | 12 | #include <utility> |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 +0000 | [diff] [blame] | 13 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 14 | #include "modules/rtp_rtcp/source/rtp_sender.h" |
Sebastian Jansson | 8e0b15b | 2018-04-18 19:19:22 +0200 | [diff] [blame] | 15 | #include "video/video_send_stream_impl.h" |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 +0000 | [diff] [blame] | 16 | |
| 17 | namespace webrtc { |
mflodman | 949c2f0 | 2015-10-16 02:31:11 -0700 | [diff] [blame] | 18 | |
Ying Wang | 3b790f3 | 2018-01-19 17:58:57 +0100 | [diff] [blame] | 19 | |
Per | 83d0910 | 2016-04-15 14:59:13 +0200 | [diff] [blame] | 20 | namespace { |
| 21 | |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 15:46:17 +0100 | [diff] [blame] | 22 | size_t CalculateMaxHeaderSize(const VideoSendStream::Config::Rtp& config) { |
| 23 | size_t header_size = kRtpHeaderSize; |
| 24 | size_t extensions_size = 0; |
| 25 | size_t fec_extensions_size = 0; |
| 26 | if (config.extensions.size() > 0) { |
| 27 | RtpHeaderExtensionMap extensions_map(config.extensions); |
| 28 | extensions_size = |
| 29 | extensions_map.GetTotalLengthInBytes(RTPSender::VideoExtensionSizes()); |
| 30 | fec_extensions_size = |
| 31 | extensions_map.GetTotalLengthInBytes(RTPSender::FecExtensionSizes()); |
| 32 | } |
| 33 | header_size += extensions_size; |
| 34 | if (config.flexfec.payload_type >= 0) { |
| 35 | // All FEC extensions again plus maximum FlexFec overhead. |
| 36 | header_size += fec_extensions_size + 32; |
| 37 | } else { |
| 38 | if (config.ulpfec.ulpfec_payload_type >= 0) { |
| 39 | // Header with all the FEC extensions will be repeated plus maximum |
| 40 | // UlpFec overhead. |
| 41 | header_size += fec_extensions_size + 18; |
| 42 | } |
| 43 | if (config.ulpfec.red_payload_type >= 0) { |
| 44 | header_size += 1; // RED header. |
| 45 | } |
| 46 | } |
| 47 | // Additional room for Rtx. |
| 48 | if (config.rtx.payload_type >= 0) |
| 49 | header_size += kRtxHeaderSize; |
| 50 | return header_size; |
| 51 | } |
| 52 | |
Peter Boström | e449915 | 2016-02-05 11:13:28 +0100 | [diff] [blame] | 53 | } // namespace |
| 54 | |
pbos@webrtc.org | 024e4d5 | 2014-05-15 10:03:24 +0000 | [diff] [blame] | 55 | namespace internal { |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 56 | |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 57 | |
pbos@webrtc.org | 2bb1bda | 2014-07-07 13:06:48 +0000 | [diff] [blame] | 58 | VideoSendStream::VideoSendStream( |
Peter Boström | 45553ae | 2015-05-08 13:54:38 +0200 | [diff] [blame] | 59 | int num_cpu_cores, |
Peter Boström | f16fcbe | 2015-04-30 12:16:05 +0200 | [diff] [blame] | 60 | ProcessThread* module_process_thread, |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 61 | rtc::TaskQueue* worker_queue, |
mflodman | e378702 | 2015-10-21 13:24:28 +0200 | [diff] [blame] | 62 | CallStats* call_stats, |
nisse | b8f9a32 | 2017-03-27 05:36:15 -0700 | [diff] [blame] | 63 | RtpTransportControllerSendInterface* transport, |
mflodman | 0e7e259 | 2015-11-12 21:02:42 -0800 | [diff] [blame] | 64 | BitrateAllocator* bitrate_allocator, |
asapersson | 35151f3 | 2016-05-02 23:44:01 -0700 | [diff] [blame] | 65 | SendDelayStats* send_delay_stats, |
terelius | adafe0b | 2016-05-26 01:58:40 -0700 | [diff] [blame] | 66 | RtcEventLog* event_log, |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 67 | VideoSendStream::Config config, |
| 68 | VideoEncoderConfig encoder_config, |
Åsa Persson | 4bece9a | 2017-10-06 10:04:04 +0200 | [diff] [blame] | 69 | const std::map<uint32_t, RtpState>& suspended_ssrcs, |
Ying Wang | 3b790f3 | 2018-01-19 17:58:57 +0100 | [diff] [blame] | 70 | const std::map<uint32_t, RtpPayloadState>& suspended_payload_states, |
Sebastian Jansson | 25e5110 | 2018-03-01 15:56:47 +0100 | [diff] [blame] | 71 | std::unique_ptr<FecController> fec_controller, |
| 72 | RateLimiter* retransmission_limiter) |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 73 | : worker_queue_(worker_queue), |
| 74 | thread_sync_event_(false /* manual_reset */, false), |
| 75 | stats_proxy_(Clock::GetRealTimeClock(), |
sprang | b4a1ae5 | 2015-12-03 08:10:08 -0800 | [diff] [blame] | 76 | config, |
| 77 | encoder_config.content_type), |
sprang | f24a064 | 2017-02-28 13:23:26 -0800 | [diff] [blame] | 78 | config_(std::move(config)), |
| 79 | content_type_(encoder_config.content_type) { |
Niels Möller | 4db138e | 2018-04-19 09:04:13 +0200 | [diff] [blame] | 80 | RTC_DCHECK(config_.encoder_settings.encoder_factory); |
| 81 | |
Niels Möller | 73f29cb | 2018-01-31 16:09:31 +0100 | [diff] [blame] | 82 | video_stream_encoder_ = rtc::MakeUnique<VideoStreamEncoder>( |
| 83 | num_cpu_cores, &stats_proxy_, |
| 84 | config_.encoder_settings, |
| 85 | config_.pre_encode_callback, |
Niels Möller | d1f7eb6 | 2018-03-28 16:40:58 +0200 | [diff] [blame] | 86 | rtc::MakeUnique<OveruseFrameDetector>(&stats_proxy_)); |
Sebastian Jansson | 06b83aa | 2018-02-28 13:03:46 +0100 | [diff] [blame] | 87 | // TODO(srte): Initialization should not be done posted on a task queue. |
| 88 | // Note that the posted task must not outlive this scope since the closure |
| 89 | // references local variables. |
| 90 | worker_queue_->PostTask(rtc::NewClosure( |
| 91 | [this, call_stats, transport, bitrate_allocator, send_delay_stats, |
| 92 | event_log, &suspended_ssrcs, &encoder_config, &suspended_payload_states, |
Sebastian Jansson | 25e5110 | 2018-03-01 15:56:47 +0100 | [diff] [blame] | 93 | &fec_controller, retransmission_limiter]() { |
Sebastian Jansson | 06b83aa | 2018-02-28 13:03:46 +0100 | [diff] [blame] | 94 | send_stream_.reset(new VideoSendStreamImpl( |
| 95 | &stats_proxy_, worker_queue_, call_stats, transport, |
| 96 | bitrate_allocator, send_delay_stats, video_stream_encoder_.get(), |
| 97 | event_log, &config_, encoder_config.max_bitrate_bps, |
| 98 | encoder_config.bitrate_priority, suspended_ssrcs, |
| 99 | suspended_payload_states, encoder_config.content_type, |
Sebastian Jansson | 25e5110 | 2018-03-01 15:56:47 +0100 | [diff] [blame] | 100 | std::move(fec_controller), retransmission_limiter)); |
Sebastian Jansson | 06b83aa | 2018-02-28 13:03:46 +0100 | [diff] [blame] | 101 | }, |
| 102 | [this]() { thread_sync_event_.Set(); })); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 103 | |
| 104 | // Wait for ConstructionTask to complete so that |send_stream_| can be used. |
| 105 | // |module_process_thread| must be registered and deregistered on the thread |
| 106 | // it was created on. |
| 107 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 108 | send_stream_->RegisterProcessThread(module_process_thread); |
sprang | 44b3ef6 | 2017-01-13 07:30:25 -0800 | [diff] [blame] | 109 | // TODO(sprang): Enable this also for regular video calls if it works well. |
| 110 | if (encoder_config.content_type == VideoEncoderConfig::ContentType::kScreen) { |
| 111 | // Only signal target bitrate for screenshare streams, for now. |
mflodman | cc3d442 | 2017-08-03 08:27:51 -0700 | [diff] [blame] | 112 | video_stream_encoder_->SetBitrateObserver(send_stream_.get()); |
sprang | 44b3ef6 | 2017-01-13 07:30:25 -0800 | [diff] [blame] | 113 | } |
Ying Wang | 38a31b0 | 2017-12-21 12:26:19 +0000 | [diff] [blame] | 114 | |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 115 | ReconfigureVideoEncoder(std::move(encoder_config)); |
| 116 | } |
| 117 | |
| 118 | VideoSendStream::~VideoSendStream() { |
| 119 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 120 | RTC_DCHECK(!send_stream_); |
| 121 | } |
| 122 | |
Seth Hampson | cc7125f | 2018-02-02 08:46:16 -0800 | [diff] [blame] | 123 | void VideoSendStream::UpdateActiveSimulcastLayers( |
| 124 | const std::vector<bool> active_layers) { |
| 125 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 126 | RTC_LOG(LS_INFO) << "VideoSendStream::UpdateActiveSimulcastLayers"; |
| 127 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 128 | worker_queue_->PostTask([this, send_stream, active_layers] { |
| 129 | send_stream->UpdateActiveSimulcastLayers(active_layers); |
| 130 | thread_sync_event_.Set(); |
| 131 | }); |
| 132 | |
| 133 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 134 | } |
| 135 | |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 136 | void VideoSendStream::Start() { |
| 137 | RTC_DCHECK_RUN_ON(&thread_checker_); |
Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 138 | RTC_LOG(LS_INFO) << "VideoSendStream::Start"; |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 139 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 140 | worker_queue_->PostTask([this, send_stream] { |
| 141 | send_stream->Start(); |
| 142 | thread_sync_event_.Set(); |
| 143 | }); |
| 144 | |
| 145 | // It is expected that after VideoSendStream::Start has been called, incoming |
mflodman | cc3d442 | 2017-08-03 08:27:51 -0700 | [diff] [blame] | 146 | // frames are not dropped in VideoStreamEncoder. To ensure this, Start has to |
| 147 | // be synchronized. |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 148 | thread_sync_event_.Wait(rtc::Event::kForever); |
| 149 | } |
| 150 | |
| 151 | void VideoSendStream::Stop() { |
| 152 | RTC_DCHECK_RUN_ON(&thread_checker_); |
Mirko Bonadei | 675513b | 2017-11-09 11:09:25 +0100 | [diff] [blame] | 153 | RTC_LOG(LS_INFO) << "VideoSendStream::Stop"; |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 154 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 155 | worker_queue_->PostTask([send_stream] { send_stream->Stop(); }); |
| 156 | } |
| 157 | |
perkj | a49cbd3 | 2016-09-16 07:53:41 -0700 | [diff] [blame] | 158 | void VideoSendStream::SetSource( |
perkj | 803d97f | 2016-11-01 11:45:46 -0700 | [diff] [blame] | 159 | rtc::VideoSourceInterface<webrtc::VideoFrame>* source, |
| 160 | const DegradationPreference& degradation_preference) { |
perkj | a49cbd3 | 2016-09-16 07:53:41 -0700 | [diff] [blame] | 161 | RTC_DCHECK_RUN_ON(&thread_checker_); |
mflodman | cc3d442 | 2017-08-03 08:27:51 -0700 | [diff] [blame] | 162 | video_stream_encoder_->SetSource(source, degradation_preference); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) { |
perkj | fa10b55 | 2016-10-02 23:45:26 -0700 | [diff] [blame] | 166 | // TODO(perkj): Some test cases in VideoSendStreamTest call |
| 167 | // ReconfigureVideoEncoder from the network thread. |
| 168 | // RTC_DCHECK_RUN_ON(&thread_checker_); |
sprang | f24a064 | 2017-02-28 13:23:26 -0800 | [diff] [blame] | 169 | RTC_DCHECK(content_type_ == config.content_type); |
Ilya Nikolaevskiy | 1d037ae | 2018-03-15 15:46:17 +0100 | [diff] [blame] | 170 | video_stream_encoder_->ConfigureEncoder( |
| 171 | std::move(config), |
| 172 | config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp), |
| 173 | config_.rtp.nack.rtp_history_ms > 0); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | VideoSendStream::Stats VideoSendStream::GetStats() { |
| 177 | // TODO(perkj, solenberg): Some test cases in EndToEndTest call GetStats from |
| 178 | // a network thread. See comment in Call::GetStats(). |
| 179 | // RTC_DCHECK_RUN_ON(&thread_checker_); |
| 180 | return stats_proxy_.GetStats(); |
| 181 | } |
| 182 | |
Sebastian Jansson | a45c8da | 2018-01-16 10:55:29 +0100 | [diff] [blame] | 183 | rtc::Optional<float> VideoSendStream::GetPacingFactorOverride() const { |
| 184 | return send_stream_->configured_pacing_factor_; |
| 185 | } |
| 186 | |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 187 | void VideoSendStream::SignalNetworkState(NetworkState state) { |
| 188 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 189 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 190 | worker_queue_->PostTask( |
| 191 | [send_stream, state] { send_stream->SignalNetworkState(state); }); |
| 192 | } |
| 193 | |
Åsa Persson | 4bece9a | 2017-10-06 10:04:04 +0200 | [diff] [blame] | 194 | void VideoSendStream::StopPermanentlyAndGetRtpStates( |
| 195 | VideoSendStream::RtpStateMap* rtp_state_map, |
| 196 | VideoSendStream::RtpPayloadStateMap* payload_state_map) { |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 197 | RTC_DCHECK_RUN_ON(&thread_checker_); |
mflodman | cc3d442 | 2017-08-03 08:27:51 -0700 | [diff] [blame] | 198 | video_stream_encoder_->Stop(); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 199 | send_stream_->DeRegisterProcessThread(); |
Sebastian Jansson | 1b2e90b | 2018-03-05 19:09:11 +0100 | [diff] [blame] | 200 | worker_queue_->PostTask([this, rtp_state_map, payload_state_map]() { |
| 201 | send_stream_->Stop(); |
| 202 | *rtp_state_map = send_stream_->GetRtpStates(); |
| 203 | *payload_state_map = send_stream_->GetRtpPayloadStates(); |
| 204 | send_stream_.reset(); |
| 205 | thread_sync_event_.Set(); |
| 206 | }); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 207 | thread_sync_event_.Wait(rtc::Event::kForever); |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 208 | } |
| 209 | |
nisse | 284542b | 2017-01-10 08:58:32 -0800 | [diff] [blame] | 210 | void VideoSendStream::SetTransportOverhead( |
| 211 | size_t transport_overhead_per_packet) { |
michaelt | 79e0588 | 2016-11-08 02:50:09 -0800 | [diff] [blame] | 212 | RTC_DCHECK_RUN_ON(&thread_checker_); |
| 213 | VideoSendStreamImpl* send_stream = send_stream_.get(); |
| 214 | worker_queue_->PostTask([send_stream, transport_overhead_per_packet] { |
| 215 | send_stream->SetTransportOverhead(transport_overhead_per_packet); |
| 216 | }); |
| 217 | } |
| 218 | |
perkj | 26091b1 | 2016-09-01 01:17:40 -0700 | [diff] [blame] | 219 | bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { |
| 220 | // Called on a network thread. |
| 221 | return send_stream_->DeliverRtcp(packet, length); |
| 222 | } |
| 223 | |
palmkvist | e75f204 | 2016-09-28 06:19:48 -0700 | [diff] [blame] | 224 | void VideoSendStream::EnableEncodedFrameRecording( |
| 225 | const std::vector<rtc::PlatformFile>& files, |
| 226 | size_t byte_limit) { |
| 227 | send_stream_->EnableEncodedFrameRecording(files, byte_limit); |
| 228 | } |
| 229 | |
pbos@webrtc.org | 29d5839 | 2013-05-16 12:08:03 +0000 | [diff] [blame] | 230 | } // namespace internal |
| 231 | } // namespace webrtc |