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 */
10 #include "video/video_send_stream.h"
11
12 #include <utility>
13
14 #include "api/array_view.h"
15 #include "api/video/video_stream_encoder_create.h"
16 #include "api/video/video_stream_encoder_settings.h"
17 #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
18 #include "modules/rtp_rtcp/source/rtp_header_extension_size.h"
19 #include "modules/rtp_rtcp/source/rtp_sender.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/strings/string_builder.h"
23 #include "rtc_base/task_utils/to_queued_task.h"
24 #include "system_wrappers/include/clock.h"
25 #include "system_wrappers/include/field_trial.h"
26 #include "video/video_send_stream_impl.h"
27
28 namespace webrtc {
29
30 namespace {
31
32 constexpr char kTargetBitrateRtcpFieldTrial[] = "WebRTC-Target-Bitrate-Rtcp";
33
CalculateMaxHeaderSize(const RtpConfig & config)34 size_t CalculateMaxHeaderSize(const RtpConfig& config) {
35 size_t header_size = kRtpHeaderSize;
36 size_t extensions_size = 0;
37 size_t fec_extensions_size = 0;
38 if (!config.extensions.empty()) {
39 RtpHeaderExtensionMap extensions_map(config.extensions);
40 extensions_size = RtpHeaderExtensionSize(RTPSender::VideoExtensionSizes(),
41 extensions_map);
42 fec_extensions_size =
43 RtpHeaderExtensionSize(RTPSender::FecExtensionSizes(), extensions_map);
44 }
45 header_size += extensions_size;
46 if (config.flexfec.payload_type >= 0) {
47 // All FEC extensions again plus maximum FlexFec overhead.
48 header_size += fec_extensions_size + 32;
49 } else {
50 if (config.ulpfec.ulpfec_payload_type >= 0) {
51 // Header with all the FEC extensions will be repeated plus maximum
52 // UlpFec overhead.
53 header_size += fec_extensions_size + 18;
54 }
55 if (config.ulpfec.red_payload_type >= 0) {
56 header_size += 1; // RED header.
57 }
58 }
59 // Additional room for Rtx.
60 if (config.rtx.payload_type >= 0)
61 header_size += kRtxHeaderSize;
62 return header_size;
63 }
64
65 } // namespace
66
67 namespace internal {
68
VideoSendStream(Clock * clock,int num_cpu_cores,ProcessThread * module_process_thread,TaskQueueFactory * task_queue_factory,RtcpRttStats * call_stats,RtpTransportControllerSendInterface * transport,BitrateAllocatorInterface * bitrate_allocator,SendDelayStats * send_delay_stats,RtcEventLog * event_log,VideoSendStream::Config config,VideoEncoderConfig encoder_config,const std::map<uint32_t,RtpState> & suspended_ssrcs,const std::map<uint32_t,RtpPayloadState> & suspended_payload_states,std::unique_ptr<FecController> fec_controller)69 VideoSendStream::VideoSendStream(
70 Clock* clock,
71 int num_cpu_cores,
72 ProcessThread* module_process_thread,
73 TaskQueueFactory* task_queue_factory,
74 RtcpRttStats* call_stats,
75 RtpTransportControllerSendInterface* transport,
76 BitrateAllocatorInterface* bitrate_allocator,
77 SendDelayStats* send_delay_stats,
78 RtcEventLog* event_log,
79 VideoSendStream::Config config,
80 VideoEncoderConfig encoder_config,
81 const std::map<uint32_t, RtpState>& suspended_ssrcs,
82 const std::map<uint32_t, RtpPayloadState>& suspended_payload_states,
83 std::unique_ptr<FecController> fec_controller)
84 : worker_queue_(transport->GetWorkerQueue()),
85 stats_proxy_(clock, config, encoder_config.content_type),
86 config_(std::move(config)),
87 content_type_(encoder_config.content_type) {
88 RTC_DCHECK(config_.encoder_settings.encoder_factory);
89 RTC_DCHECK(config_.encoder_settings.bitrate_allocator_factory);
90
91 video_stream_encoder_ =
92 CreateVideoStreamEncoder(clock, task_queue_factory, num_cpu_cores,
93 &stats_proxy_, config_.encoder_settings);
94 // TODO(srte): Initialization should not be done posted on a task queue.
95 // Note that the posted task must not outlive this scope since the closure
96 // references local variables.
97 worker_queue_->PostTask(ToQueuedTask(
98 [this, clock, call_stats, transport, bitrate_allocator, send_delay_stats,
99 event_log, &suspended_ssrcs, &encoder_config, &suspended_payload_states,
100 &fec_controller]() {
101 send_stream_.reset(new VideoSendStreamImpl(
102 clock, &stats_proxy_, worker_queue_, call_stats, transport,
103 bitrate_allocator, send_delay_stats, video_stream_encoder_.get(),
104 event_log, &config_, encoder_config.max_bitrate_bps,
105 encoder_config.bitrate_priority, suspended_ssrcs,
106 suspended_payload_states, encoder_config.content_type,
107 std::move(fec_controller)));
108 },
109 [this]() { thread_sync_event_.Set(); }));
110
111 // Wait for ConstructionTask to complete so that |send_stream_| can be used.
112 // |module_process_thread| must be registered and deregistered on the thread
113 // it was created on.
114 thread_sync_event_.Wait(rtc::Event::kForever);
115 send_stream_->RegisterProcessThread(module_process_thread);
116 // TODO(sprang): Enable this also for regular video calls by default, if it
117 // works well.
118 if (encoder_config.content_type == VideoEncoderConfig::ContentType::kScreen ||
119 field_trial::IsEnabled(kTargetBitrateRtcpFieldTrial)) {
120 video_stream_encoder_->SetBitrateAllocationObserver(send_stream_.get());
121 }
122
123 ReconfigureVideoEncoder(std::move(encoder_config));
124 }
125
~VideoSendStream()126 VideoSendStream::~VideoSendStream() {
127 RTC_DCHECK_RUN_ON(&thread_checker_);
128 RTC_DCHECK(!send_stream_);
129 }
130
UpdateActiveSimulcastLayers(const std::vector<bool> active_layers)131 void VideoSendStream::UpdateActiveSimulcastLayers(
132 const std::vector<bool> active_layers) {
133 RTC_DCHECK_RUN_ON(&thread_checker_);
134
135 rtc::StringBuilder active_layers_string;
136 active_layers_string << "{";
137 for (size_t i = 0; i < active_layers.size(); ++i) {
138 if (active_layers[i]) {
139 active_layers_string << "1";
140 } else {
141 active_layers_string << "0";
142 }
143 if (i < active_layers.size() - 1) {
144 active_layers_string << ", ";
145 }
146 }
147 active_layers_string << "}";
148 RTC_LOG(LS_INFO) << "UpdateActiveSimulcastLayers: "
149 << active_layers_string.str();
150
151 VideoSendStreamImpl* send_stream = send_stream_.get();
152 worker_queue_->PostTask([this, send_stream, active_layers] {
153 send_stream->UpdateActiveSimulcastLayers(active_layers);
154 thread_sync_event_.Set();
155 });
156
157 thread_sync_event_.Wait(rtc::Event::kForever);
158 }
159
Start()160 void VideoSendStream::Start() {
161 RTC_DCHECK_RUN_ON(&thread_checker_);
162 RTC_LOG(LS_INFO) << "VideoSendStream::Start";
163 VideoSendStreamImpl* send_stream = send_stream_.get();
164 worker_queue_->PostTask([this, send_stream] {
165 send_stream->Start();
166 thread_sync_event_.Set();
167 });
168
169 // It is expected that after VideoSendStream::Start has been called, incoming
170 // frames are not dropped in VideoStreamEncoder. To ensure this, Start has to
171 // be synchronized.
172 thread_sync_event_.Wait(rtc::Event::kForever);
173 }
174
Stop()175 void VideoSendStream::Stop() {
176 RTC_DCHECK_RUN_ON(&thread_checker_);
177 RTC_LOG(LS_INFO) << "VideoSendStream::Stop";
178 VideoSendStreamImpl* send_stream = send_stream_.get();
179 worker_queue_->PostTask([send_stream] { send_stream->Stop(); });
180 }
181
AddAdaptationResource(rtc::scoped_refptr<Resource> resource)182 void VideoSendStream::AddAdaptationResource(
183 rtc::scoped_refptr<Resource> resource) {
184 RTC_DCHECK_RUN_ON(&thread_checker_);
185 video_stream_encoder_->AddAdaptationResource(resource);
186 }
187
188 std::vector<rtc::scoped_refptr<Resource>>
GetAdaptationResources()189 VideoSendStream::GetAdaptationResources() {
190 RTC_DCHECK_RUN_ON(&thread_checker_);
191 return video_stream_encoder_->GetAdaptationResources();
192 }
193
SetSource(rtc::VideoSourceInterface<webrtc::VideoFrame> * source,const DegradationPreference & degradation_preference)194 void VideoSendStream::SetSource(
195 rtc::VideoSourceInterface<webrtc::VideoFrame>* source,
196 const DegradationPreference& degradation_preference) {
197 RTC_DCHECK_RUN_ON(&thread_checker_);
198 video_stream_encoder_->SetSource(source, degradation_preference);
199 }
200
ReconfigureVideoEncoder(VideoEncoderConfig config)201 void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) {
202 // TODO(perkj): Some test cases in VideoSendStreamTest call
203 // ReconfigureVideoEncoder from the network thread.
204 // RTC_DCHECK_RUN_ON(&thread_checker_);
205 RTC_DCHECK(content_type_ == config.content_type);
206 video_stream_encoder_->ConfigureEncoder(
207 std::move(config),
208 config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp));
209 }
210
GetStats()211 VideoSendStream::Stats VideoSendStream::GetStats() {
212 // TODO(perkj, solenberg): Some test cases in EndToEndTest call GetStats from
213 // a network thread. See comment in Call::GetStats().
214 // RTC_DCHECK_RUN_ON(&thread_checker_);
215 return stats_proxy_.GetStats();
216 }
217
GetPacingFactorOverride() const218 absl::optional<float> VideoSendStream::GetPacingFactorOverride() const {
219 return send_stream_->configured_pacing_factor_;
220 }
221
StopPermanentlyAndGetRtpStates(VideoSendStream::RtpStateMap * rtp_state_map,VideoSendStream::RtpPayloadStateMap * payload_state_map)222 void VideoSendStream::StopPermanentlyAndGetRtpStates(
223 VideoSendStream::RtpStateMap* rtp_state_map,
224 VideoSendStream::RtpPayloadStateMap* payload_state_map) {
225 RTC_DCHECK_RUN_ON(&thread_checker_);
226 video_stream_encoder_->Stop();
227 send_stream_->DeRegisterProcessThread();
228 worker_queue_->PostTask([this, rtp_state_map, payload_state_map]() {
229 send_stream_->Stop();
230 *rtp_state_map = send_stream_->GetRtpStates();
231 *payload_state_map = send_stream_->GetRtpPayloadStates();
232 send_stream_.reset();
233 thread_sync_event_.Set();
234 });
235 thread_sync_event_.Wait(rtc::Event::kForever);
236 }
237
DeliverRtcp(const uint8_t * packet,size_t length)238 void VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
239 // Called on a network thread.
240 send_stream_->DeliverRtcp(packet, length);
241 }
242
243 } // namespace internal
244 } // namespace webrtc
245