blob: 840991b4baceadf16fe026bd02915d816aa84da8 [file] [log] [blame]
pbos@webrtc.org29d58392013-05-16 12:08:03 +00001/*
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
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000011#include "webrtc/video/video_send_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000012
pbos@webrtc.orgdde16f12014-08-05 23:35:43 +000013#include <algorithm>
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +000014#include <sstream>
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +000015#include <string>
pbos@webrtc.org29d58392013-05-16 12:08:03 +000016#include <vector>
17
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +000018#include "webrtc/base/checks.h"
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.h"
tommie4f96502015-10-20 23:00:48 -070020#include "webrtc/base/trace_event.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000021#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
mflodman0e7e2592015-11-12 21:02:42 -080022#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
Stefan Holmer80e12072016-02-23 13:30:42 +010023#include "webrtc/modules/congestion_controller/include/congestion_controller.h"
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010024#include "webrtc/modules/pacing/packet_router.h"
Peter Boström9c017252016-02-26 16:26:20 +010025#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
Peter Boströme4499152016-02-05 11:13:28 +010026#include "webrtc/modules/utility/include/process_thread.h"
perkj600246e2016-05-04 11:26:51 -070027#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
Peter Boström7623ce42015-12-09 12:13:30 +010028#include "webrtc/video/call_stats.h"
Peter Boström4b91bd02015-06-26 06:58:16 +020029#include "webrtc/video/video_capture_input.h"
Stefan Holmer58c664c2016-02-08 14:31:30 +010030#include "webrtc/video/vie_remb.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000031#include "webrtc/video_send_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000032
33namespace webrtc {
mflodman949c2f02015-10-16 02:31:11 -070034
mflodman949c2f02015-10-16 02:31:11 -070035class RtcpIntraFrameObserver;
36class TransportFeedbackObserver;
37
Per83d09102016-04-15 14:59:13 +020038static const int kMinSendSidePacketHistorySize = 600;
39
40namespace {
41
42std::vector<RtpRtcp*> CreateRtpRtcpModules(
43 Transport* outgoing_transport,
44 RtcpIntraFrameObserver* intra_frame_callback,
45 RtcpBandwidthObserver* bandwidth_callback,
46 TransportFeedbackObserver* transport_feedback_callback,
47 RtcpRttStats* rtt_stats,
48 RtpPacketSender* paced_sender,
49 TransportSequenceNumberAllocator* transport_sequence_number_allocator,
50 SendStatisticsProxy* stats_proxy,
asapersson35151f32016-05-02 23:44:01 -070051 SendDelayStats* send_delay_stats,
Per83d09102016-04-15 14:59:13 +020052 size_t num_modules) {
53 RTC_DCHECK_GT(num_modules, 0u);
54 RtpRtcp::Configuration configuration;
55 ReceiveStatistics* null_receive_statistics = configuration.receive_statistics;
56 configuration.audio = false;
57 configuration.receiver_only = false;
58 configuration.receive_statistics = null_receive_statistics;
59 configuration.outgoing_transport = outgoing_transport;
60 configuration.intra_frame_callback = intra_frame_callback;
61 configuration.rtt_stats = rtt_stats;
62 configuration.rtcp_packet_type_counter_observer = stats_proxy;
63 configuration.paced_sender = paced_sender;
64 configuration.transport_sequence_number_allocator =
65 transport_sequence_number_allocator;
66 configuration.send_bitrate_observer = stats_proxy;
67 configuration.send_frame_count_observer = stats_proxy;
68 configuration.send_side_delay_observer = stats_proxy;
asapersson35151f32016-05-02 23:44:01 -070069 configuration.send_packet_observer = send_delay_stats;
Per83d09102016-04-15 14:59:13 +020070 configuration.bandwidth_callback = bandwidth_callback;
71 configuration.transport_feedback_callback = transport_feedback_callback;
72
73 std::vector<RtpRtcp*> modules;
74 for (size_t i = 0; i < num_modules; ++i) {
75 RtpRtcp* rtp_rtcp = RtpRtcp::CreateRtpRtcp(configuration);
76 rtp_rtcp->SetSendingStatus(false);
77 rtp_rtcp->SetSendingMediaStatus(false);
78 rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
79 modules.push_back(rtp_rtcp);
80 }
81 return modules;
82}
83
84} // namespace
85
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +000086std::string
pbos@webrtc.org024e4d52014-05-15 10:03:24 +000087VideoSendStream::Config::EncoderSettings::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +000088 std::stringstream ss;
89 ss << "{payload_name: " << payload_name;
90 ss << ", payload_type: " << payload_type;
Peter Boström74f6e9e2016-04-04 17:56:10 +020091 ss << ", encoder: " << (encoder ? "(VideoEncoder)" : "nullptr");
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +000092 ss << '}';
93 return ss.str();
94}
95
pbos@webrtc.org024e4d52014-05-15 10:03:24 +000096std::string VideoSendStream::Config::Rtp::Rtx::ToString()
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +000097 const {
98 std::stringstream ss;
pbos@webrtc.org32e85282015-01-15 10:09:39 +000099 ss << "{ssrcs: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000100 for (size_t i = 0; i < ssrcs.size(); ++i) {
101 ss << ssrcs[i];
102 if (i != ssrcs.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000103 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000104 }
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000105 ss << ']';
andrew@webrtc.org8f27fcc2015-01-09 20:22:46 +0000106
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000107 ss << ", payload_type: " << payload_type;
108 ss << '}';
109 return ss.str();
110}
111
pbos@webrtc.org024e4d52014-05-15 10:03:24 +0000112std::string VideoSendStream::Config::Rtp::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000113 std::stringstream ss;
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000114 ss << "{ssrcs: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000115 for (size_t i = 0; i < ssrcs.size(); ++i) {
116 ss << ssrcs[i];
117 if (i != ssrcs.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000118 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000119 }
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000120 ss << ']';
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700121 ss << ", rtcp_mode: "
122 << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound"
123 : "RtcpMode::kReducedSize");
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000124 ss << ", max_packet_size: " << max_packet_size;
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000125 ss << ", extensions: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000126 for (size_t i = 0; i < extensions.size(); ++i) {
127 ss << extensions[i].ToString();
128 if (i != extensions.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000129 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000130 }
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000131 ss << ']';
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000132
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000133 ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
134 ss << ", fec: " << fec.ToString();
135 ss << ", rtx: " << rtx.ToString();
136 ss << ", c_name: " << c_name;
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000137 ss << '}';
138 return ss.str();
139}
140
pbos@webrtc.org024e4d52014-05-15 10:03:24 +0000141std::string VideoSendStream::Config::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000142 std::stringstream ss;
143 ss << "{encoder_settings: " << encoder_settings.ToString();
144 ss << ", rtp: " << rtp.ToString();
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000145 ss << ", pre_encode_callback: "
Peter Boström74f6e9e2016-04-04 17:56:10 +0200146 << (pre_encode_callback ? "(I420FrameCallback)" : "nullptr");
147 ss << ", post_encode_callback: "
148 << (post_encode_callback ? "(EncodedFrameObserver)" : "nullptr");
149 ss << ", local_renderer: "
150 << (local_renderer ? "(VideoRenderer)" : "nullptr");
pbos@webrtc.org32e85282015-01-15 10:09:39 +0000151 ss << ", render_delay_ms: " << render_delay_ms;
152 ss << ", target_delay_ms: " << target_delay_ms;
153 ss << ", suspend_below_min_bitrate: " << (suspend_below_min_bitrate ? "on"
154 : "off");
pbos@webrtc.org1e92b0a2014-05-15 09:35:06 +0000155 ss << '}';
156 return ss.str();
157}
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000158
Peter Boströme4499152016-02-05 11:13:28 +0100159namespace {
160
Peter Boström39593972016-02-15 11:27:15 +0100161VideoCodecType PayloadNameToCodecType(const std::string& payload_name) {
162 if (payload_name == "VP8")
163 return kVideoCodecVP8;
164 if (payload_name == "VP9")
165 return kVideoCodecVP9;
166 if (payload_name == "H264")
167 return kVideoCodecH264;
168 return kVideoCodecGeneric;
169}
170
171bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
172 switch (PayloadNameToCodecType(payload_name)) {
173 case kVideoCodecVP8:
174 case kVideoCodecVP9:
175 return true;
176 case kVideoCodecH264:
177 case kVideoCodecGeneric:
178 return false;
179 case kVideoCodecI420:
180 case kVideoCodecRED:
181 case kVideoCodecULPFEC:
182 case kVideoCodecUnknown:
183 RTC_NOTREACHED();
184 return false;
185 }
186 RTC_NOTREACHED();
187 return false;
188}
189
Peter Boström23353ab2016-02-24 15:19:55 +0100190// TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
191// pipelining encoders better (multiple input frames before something comes
192// out). This should effectively turn off CPU adaptations for systems that
193// remotely cope with the load right now.
Peter Boströme4499152016-02-05 11:13:28 +0100194CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
195 CpuOveruseOptions options;
196 if (full_overuse_time) {
Peter Boström23353ab2016-02-24 15:19:55 +0100197 options.low_encode_usage_threshold_percent = 150;
198 options.high_encode_usage_threshold_percent = 200;
Peter Boströme4499152016-02-05 11:13:28 +0100199 }
200 return options;
201}
pbos14fe7082016-04-20 06:35:56 -0700202
203VideoCodec VideoEncoderConfigToVideoCodec(const VideoEncoderConfig& config,
204 const std::string& payload_name,
205 int payload_type) {
206 const std::vector<VideoStream>& streams = config.streams;
207 static const int kEncoderMinBitrateKbps = 30;
208 RTC_DCHECK(!streams.empty());
209 RTC_DCHECK_GE(config.min_transmit_bitrate_bps, 0);
210
211 VideoCodec video_codec;
212 memset(&video_codec, 0, sizeof(video_codec));
213 video_codec.codecType = PayloadNameToCodecType(payload_name);
214
215 switch (config.content_type) {
216 case VideoEncoderConfig::ContentType::kRealtimeVideo:
217 video_codec.mode = kRealtimeVideo;
218 break;
219 case VideoEncoderConfig::ContentType::kScreen:
220 video_codec.mode = kScreensharing;
221 if (config.streams.size() == 1 &&
222 config.streams[0].temporal_layer_thresholds_bps.size() == 1) {
223 video_codec.targetBitrate =
224 config.streams[0].temporal_layer_thresholds_bps[0] / 1000;
225 }
226 break;
227 }
228
229 switch (video_codec.codecType) {
230 case kVideoCodecVP8: {
231 if (config.encoder_specific_settings) {
232 video_codec.codecSpecific.VP8 = *reinterpret_cast<const VideoCodecVP8*>(
233 config.encoder_specific_settings);
234 } else {
235 video_codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
236 }
237 video_codec.codecSpecific.VP8.numberOfTemporalLayers =
238 static_cast<unsigned char>(
239 streams.back().temporal_layer_thresholds_bps.size() + 1);
240 break;
241 }
242 case kVideoCodecVP9: {
243 if (config.encoder_specific_settings) {
244 video_codec.codecSpecific.VP9 = *reinterpret_cast<const VideoCodecVP9*>(
245 config.encoder_specific_settings);
246 if (video_codec.mode == kScreensharing) {
247 video_codec.codecSpecific.VP9.flexibleMode = true;
248 // For now VP9 screensharing use 1 temporal and 2 spatial layers.
249 RTC_DCHECK_EQ(video_codec.codecSpecific.VP9.numberOfTemporalLayers,
250 1);
251 RTC_DCHECK_EQ(video_codec.codecSpecific.VP9.numberOfSpatialLayers, 2);
252 }
253 } else {
254 video_codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
255 }
256 video_codec.codecSpecific.VP9.numberOfTemporalLayers =
257 static_cast<unsigned char>(
258 streams.back().temporal_layer_thresholds_bps.size() + 1);
259 break;
260 }
261 case kVideoCodecH264: {
262 if (config.encoder_specific_settings) {
263 video_codec.codecSpecific.H264 =
264 *reinterpret_cast<const VideoCodecH264*>(
265 config.encoder_specific_settings);
266 } else {
267 video_codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
268 }
269 break;
270 }
271 default:
272 // TODO(pbos): Support encoder_settings codec-agnostically.
273 RTC_DCHECK(!config.encoder_specific_settings)
274 << "Encoder-specific settings for codec type not wired up.";
275 break;
276 }
277
278 strncpy(video_codec.plName, payload_name.c_str(), kPayloadNameSize - 1);
279 video_codec.plName[kPayloadNameSize - 1] = '\0';
280 video_codec.plType = payload_type;
281 video_codec.numberOfSimulcastStreams =
282 static_cast<unsigned char>(streams.size());
283 video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
284 if (video_codec.minBitrate < kEncoderMinBitrateKbps)
285 video_codec.minBitrate = kEncoderMinBitrateKbps;
286 RTC_DCHECK_LE(streams.size(), static_cast<size_t>(kMaxSimulcastStreams));
287 if (video_codec.codecType == kVideoCodecVP9) {
288 // If the vector is empty, bitrates will be configured automatically.
289 RTC_DCHECK(config.spatial_layers.empty() ||
290 config.spatial_layers.size() ==
291 video_codec.codecSpecific.VP9.numberOfSpatialLayers);
292 RTC_DCHECK_LE(video_codec.codecSpecific.VP9.numberOfSpatialLayers,
293 kMaxSimulcastStreams);
294 for (size_t i = 0; i < config.spatial_layers.size(); ++i)
295 video_codec.spatialLayers[i] = config.spatial_layers[i];
296 }
297 for (size_t i = 0; i < streams.size(); ++i) {
298 SimulcastStream* sim_stream = &video_codec.simulcastStream[i];
299 RTC_DCHECK_GT(streams[i].width, 0u);
300 RTC_DCHECK_GT(streams[i].height, 0u);
301 RTC_DCHECK_GT(streams[i].max_framerate, 0);
302 // Different framerates not supported per stream at the moment.
303 RTC_DCHECK_EQ(streams[i].max_framerate, streams[0].max_framerate);
304 RTC_DCHECK_GE(streams[i].min_bitrate_bps, 0);
305 RTC_DCHECK_GE(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps);
306 RTC_DCHECK_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps);
307 RTC_DCHECK_GE(streams[i].max_qp, 0);
308
309 sim_stream->width = static_cast<uint16_t>(streams[i].width);
310 sim_stream->height = static_cast<uint16_t>(streams[i].height);
311 sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000;
312 sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000;
313 sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000;
314 sim_stream->qpMax = streams[i].max_qp;
315 sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
316 streams[i].temporal_layer_thresholds_bps.size() + 1);
317
318 video_codec.width = std::max(video_codec.width,
319 static_cast<uint16_t>(streams[i].width));
320 video_codec.height = std::max(
321 video_codec.height, static_cast<uint16_t>(streams[i].height));
322 video_codec.minBitrate =
323 std::min(static_cast<uint16_t>(video_codec.minBitrate),
324 static_cast<uint16_t>(streams[i].min_bitrate_bps / 1000));
325 video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000;
326 video_codec.qpMax = std::max(video_codec.qpMax,
327 static_cast<unsigned int>(streams[i].max_qp));
328 }
329
330 if (video_codec.maxBitrate == 0) {
331 // Unset max bitrate -> cap to one bit per pixel.
332 video_codec.maxBitrate =
333 (video_codec.width * video_codec.height * video_codec.maxFramerate) /
334 1000;
335 }
336 if (video_codec.maxBitrate < kEncoderMinBitrateKbps)
337 video_codec.maxBitrate = kEncoderMinBitrateKbps;
338
339 RTC_DCHECK_GT(streams[0].max_framerate, 0);
340 video_codec.maxFramerate = streams[0].max_framerate;
341
342 return video_codec;
343}
344
Peter Boströme4499152016-02-05 11:13:28 +0100345} // namespace
346
pbos@webrtc.org024e4d52014-05-15 10:03:24 +0000347namespace internal {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000348VideoSendStream::VideoSendStream(
Peter Boström45553ae2015-05-08 13:54:38 +0200349 int num_cpu_cores,
Peter Boströmf16fcbe2015-04-30 12:16:05 +0200350 ProcessThread* module_process_thread,
mflodmane3787022015-10-21 13:24:28 +0200351 CallStats* call_stats,
mflodman0c478b32015-10-21 15:52:16 +0200352 CongestionController* congestion_controller,
mflodman0e7e2592015-11-12 21:02:42 -0800353 BitrateAllocator* bitrate_allocator,
asapersson35151f32016-05-02 23:44:01 -0700354 SendDelayStats* send_delay_stats,
mflodman86aabb22016-03-11 15:44:32 +0100355 VieRemb* remb,
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000356 const VideoSendStream::Config& config,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000357 const VideoEncoderConfig& encoder_config,
Peter Boström45553ae2015-05-08 13:54:38 +0200358 const std::map<uint32_t, RtpState>& suspended_ssrcs)
sprangb4a1ae52015-12-03 08:10:08 -0800359 : stats_proxy_(Clock::GetRealTimeClock(),
360 config,
361 encoder_config.content_type),
sprang@webrtc.org40709352013-11-26 11:41:59 +0000362 encoded_frame_proxy_(config.post_encode_callback),
pbos@webrtc.org64887612013-11-14 08:58:14 +0000363 config_(config),
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000364 suspended_ssrcs_(suspended_ssrcs),
Peter Boströmf16fcbe2015-04-30 12:16:05 +0200365 module_process_thread_(module_process_thread),
mflodmane3787022015-10-21 13:24:28 +0200366 call_stats_(call_stats),
mflodman0c478b32015-10-21 15:52:16 +0200367 congestion_controller_(congestion_controller),
mflodman86aabb22016-03-11 15:44:32 +0100368 bitrate_allocator_(bitrate_allocator),
Stefan Holmer58c664c2016-02-08 14:31:30 +0100369 remb_(remb),
Peter Boströma4c76882016-03-03 16:29:02 +0100370 encoder_thread_(EncoderThreadFunction, this, "EncoderThread"),
371 encoder_wakeup_event_(false, false),
372 stop_encoder_thread_(0),
Peter Boströme4499152016-02-05 11:13:28 +0100373 overuse_detector_(
374 Clock::GetRealTimeClock(),
375 GetCpuOveruseOptions(config.encoder_settings.full_overuse_time),
376 this,
377 config.post_encode_callback,
378 &stats_proxy_),
perkjbc75d972016-05-02 06:31:25 -0700379 vie_encoder_(num_cpu_cores,
perkjbc75d972016-05-02 06:31:25 -0700380 module_process_thread_,
381 &stats_proxy_,
Per28a44562016-05-04 17:12:51 +0200382 &overuse_detector_),
perkj600246e2016-05-04 11:26:51 -0700383 encoder_feedback_(Clock::GetRealTimeClock(),
384 config.rtp.ssrcs,
385 &vie_encoder_),
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200386 video_sender_(vie_encoder_.video_sender()),
Per83d09102016-04-15 14:59:13 +0200387 bandwidth_observer_(congestion_controller_->GetBitrateController()
388 ->CreateRtcpBandwidthObserver()),
389 rtp_rtcp_modules_(CreateRtpRtcpModules(
390 config.send_transport,
391 &encoder_feedback_,
392 bandwidth_observer_.get(),
393 congestion_controller_->GetTransportFeedbackObserver(),
394 call_stats_->rtcp_rtt_stats(),
395 congestion_controller_->pacer(),
396 congestion_controller_->packet_router(),
397 &stats_proxy_,
asapersson35151f32016-05-02 23:44:01 -0700398 send_delay_stats,
Per83d09102016-04-15 14:59:13 +0200399 config_.rtp.ssrcs.size())),
kjellander02b3d272016-04-20 05:05:54 -0700400 payload_router_(rtp_rtcp_modules_, config.encoder_settings.payload_type),
Peter Boströma4c76882016-03-03 16:29:02 +0100401 input_(&encoder_wakeup_event_,
Peter Boström8c66a002016-02-11 13:51:10 +0100402 config_.local_renderer,
403 &stats_proxy_,
404 &overuse_detector_) {
pbosa2f30de2015-10-15 05:22:13 -0700405 LOG(LS_INFO) << "VideoSendStream: " << config_.ToString();
Stefan Holmer58c664c2016-02-08 14:31:30 +0100406
henrikg91d6ede2015-09-17 00:24:34 -0700407 RTC_DCHECK(!config_.rtp.ssrcs.empty());
Stefan Holmer58c664c2016-02-08 14:31:30 +0100408 RTC_DCHECK(module_process_thread_);
409 RTC_DCHECK(call_stats_);
410 RTC_DCHECK(congestion_controller_);
411 RTC_DCHECK(remb_);
mflodman949c2f02015-10-16 02:31:11 -0700412
mflodman949c2f02015-10-16 02:31:11 -0700413
Per83d09102016-04-15 14:59:13 +0200414 // RTP/RTCP initialization.
415 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
416 module_process_thread_->RegisterModule(rtp_rtcp);
417 congestion_controller_->packet_router()->AddRtpModule(rtp_rtcp);
418 }
mflodman949c2f02015-10-16 02:31:11 -0700419
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200420 video_sender_->RegisterProtectionCallback(this);
mflodman949c2f02015-10-16 02:31:11 -0700421
pbos@webrtc.org29023282013-09-11 10:14:56 +0000422 for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
423 const std::string& extension = config_.rtp.extensions[i].name;
424 int id = config_.rtp.extensions[i].id;
Peter Boström23914fe2015-03-31 15:08:04 +0200425 // One-byte-extension local identifiers are in the range 1-14 inclusive.
henrikg91d6ede2015-09-17 00:24:34 -0700426 RTC_DCHECK_GE(id, 1);
427 RTC_DCHECK_LE(id, 14);
Peter Boström9c017252016-02-26 16:26:20 +0100428 RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension));
429 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
430 RTC_CHECK_EQ(0, rtp_rtcp->RegisterSendRtpHeaderExtension(
431 StringToRtpExtensionType(extension), id));
pbos@webrtc.org29023282013-09-11 10:14:56 +0000432 }
433 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000434
Peter Boström723ead82016-02-22 15:14:01 +0100435 remb_->AddRembSender(rtp_rtcp_modules_[0]);
436 rtp_rtcp_modules_[0]->SetREMBStatus(true);
mflodman@webrtc.org92c27932013-12-13 16:36:28 +0000437
Per83d09102016-04-15 14:59:13 +0200438 ConfigureProtection();
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000439 ConfigureSsrcs();
440
Peter Boström723ead82016-02-22 15:14:01 +0100441 // TODO(pbos): Should we set CNAME on all RTP modules?
442 rtp_rtcp_modules_.front()->SetCNAME(config_.rtp.c_name.c_str());
sprang@webrtc.org25fce9a2013-10-16 13:29:14 +0000443 // 28 to match packet overhead in ModuleRtpRtcpImpl.
Peter Boström723ead82016-02-22 15:14:01 +0100444 static const size_t kRtpPacketSizeOverhead = 28;
445 RTC_DCHECK_LE(config_.rtp.max_packet_size, 0xFFFFu + kRtpPacketSizeOverhead);
446 const uint16_t mtu = static_cast<uint16_t>(config_.rtp.max_packet_size +
447 kRtpPacketSizeOverhead);
448 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
449 rtp_rtcp->RegisterRtcpStatisticsCallback(&stats_proxy_);
450 rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(&stats_proxy_);
451 rtp_rtcp->SetMaxTransferUnit(mtu);
Peter Boström8b79b072016-02-26 16:31:37 +0100452 rtp_rtcp->RegisterVideoSendPayload(
453 config_.encoder_settings.payload_type,
454 config_.encoder_settings.payload_name.c_str());
Peter Boström723ead82016-02-22 15:14:01 +0100455 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000456
Peter Boström74f6e9e2016-04-04 17:56:10 +0200457 RTC_DCHECK(config.encoder_settings.encoder);
henrikg91d6ede2015-09-17 00:24:34 -0700458 RTC_DCHECK_GE(config.encoder_settings.payload_type, 0);
459 RTC_DCHECK_LE(config.encoder_settings.payload_type, 127);
Peter Boström905f8e72016-03-02 16:59:56 +0100460 ReconfigureVideoEncoder(encoder_config);
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +0000461
Peter Boströme4499152016-02-05 11:13:28 +0100462 module_process_thread_->RegisterModule(&overuse_detector_);
Peter Boströma4c76882016-03-03 16:29:02 +0100463
464 encoder_thread_.Start();
465 encoder_thread_.SetPriority(rtc::kHighPriority);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000466}
467
468VideoSendStream::~VideoSendStream() {
pbosa2f30de2015-10-15 05:22:13 -0700469 LOG(LS_INFO) << "~VideoSendStream: " << config_.ToString();
mflodman86aabb22016-03-11 15:44:32 +0100470
Peter Boströmca835252016-02-11 15:59:46 +0100471 Stop();
472
Peter Boströma4c76882016-03-03 16:29:02 +0100473 // Stop the encoder thread permanently.
474 rtc::AtomicOps::ReleaseStore(&stop_encoder_thread_, 1);
475 encoder_wakeup_event_.Set();
476 encoder_thread_.Stop();
477
deadbeef62411a22016-03-20 14:24:49 -0700478 // This needs to happen after stopping the encoder thread,
479 // since the encoder thread calls AddObserver.
480 bitrate_allocator_->RemoveObserver(this);
481
Peter Boströme4499152016-02-05 11:13:28 +0100482 module_process_thread_->DeRegisterModule(&overuse_detector_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000483
Peter Boström723ead82016-02-22 15:14:01 +0100484 rtp_rtcp_modules_[0]->SetREMBStatus(false);
485 remb_->RemoveRembSender(rtp_rtcp_modules_[0]);
mflodman949c2f02015-10-16 02:31:11 -0700486
Per83d09102016-04-15 14:59:13 +0200487 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
488 congestion_controller_->packet_router()->RemoveRtpModule(rtp_rtcp);
489 module_process_thread_->DeRegisterModule(rtp_rtcp);
490 delete rtp_rtcp;
491 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000492}
493
pbos1ba8d392016-05-01 20:18:34 -0700494void VideoSendStream::SignalNetworkState(NetworkState state) {
495 // When network goes up, enable RTCP status before setting transmission state.
496 // When it goes down, disable RTCP afterwards. This ensures that any packets
497 // sent due to the network state changed will not be dropped.
498 if (state == kNetworkUp) {
499 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
500 rtp_rtcp->SetRTCPStatus(config_.rtp.rtcp_mode);
501 }
502 vie_encoder_.SetNetworkTransmissionState(state == kNetworkUp);
503 if (state == kNetworkDown) {
504 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
505 rtp_rtcp->SetRTCPStatus(RtcpMode::kOff);
506 }
507}
508
509bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
510 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
511 rtp_rtcp->IncomingRtcpPacket(packet, length);
512 return true;
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000513}
514
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000515void VideoSendStream::Start() {
Peter Boström0a9fc052016-03-02 16:24:10 +0100516 if (payload_router_.active())
517 return;
Peter Boströmdabc9442016-04-11 11:45:14 +0200518 TRACE_EVENT_INSTANT0("webrtc", "VideoSendStream::Start");
Peter Boström0a9fc052016-03-02 16:24:10 +0100519 payload_router_.set_active(true);
520 // Was not already started, trigger a keyframe.
521 vie_encoder_.SendKeyFrame();
perkjbc75d972016-05-02 06:31:25 -0700522 vie_encoder_.Start();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000523}
524
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000525void VideoSendStream::Stop() {
Peter Boström0a9fc052016-03-02 16:24:10 +0100526 if (!payload_router_.active())
527 return;
Peter Boströmdabc9442016-04-11 11:45:14 +0200528 TRACE_EVENT_INSTANT0("webrtc", "VideoSendStream::Stop");
perkjbc75d972016-05-02 06:31:25 -0700529 vie_encoder_.Pause();
Peter Boström0a9fc052016-03-02 16:24:10 +0100530 payload_router_.set_active(false);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000531}
532
pbos1ba8d392016-05-01 20:18:34 -0700533VideoCaptureInput* VideoSendStream::Input() {
534 return &input_;
535}
536
Peter Boströma4c76882016-03-03 16:29:02 +0100537bool VideoSendStream::EncoderThreadFunction(void* obj) {
538 static_cast<VideoSendStream*>(obj)->EncoderProcess();
539 // We're done, return false to abort.
540 return false;
541}
542
543void VideoSendStream::EncoderProcess() {
pbos14fe7082016-04-20 06:35:56 -0700544 RTC_CHECK_EQ(0, vie_encoder_.RegisterExternalEncoder(
545 config_.encoder_settings.encoder,
546 config_.encoder_settings.payload_type,
547 config_.encoder_settings.internal_source));
548
Peter Boströma4c76882016-03-03 16:29:02 +0100549 while (true) {
550 encoder_wakeup_event_.Wait(rtc::Event::kForever);
551 if (rtc::AtomicOps::AcquireLoad(&stop_encoder_thread_))
pbos14fe7082016-04-20 06:35:56 -0700552 break;
553 rtc::Optional<EncoderSettings> encoder_settings;
554 {
555 rtc::CritScope lock(&encoder_settings_crit_);
556 if (pending_encoder_settings_) {
557 encoder_settings = pending_encoder_settings_;
558 pending_encoder_settings_ = rtc::Optional<EncoderSettings>();
559 }
560 }
561 if (encoder_settings) {
562 encoder_settings->video_codec.startBitrate =
563 bitrate_allocator_->AddObserver(
564 this, encoder_settings->video_codec.minBitrate * 1000,
565 encoder_settings->video_codec.maxBitrate * 1000) /
566 1000;
perkjbc75d972016-05-02 06:31:25 -0700567
568 payload_router_.SetSendStreams(encoder_settings->streams);
pbos14fe7082016-04-20 06:35:56 -0700569 vie_encoder_.SetEncoder(encoder_settings->video_codec,
perkjbc75d972016-05-02 06:31:25 -0700570 encoder_settings->min_transmit_bitrate_bps,
571 payload_router_.MaxPayloadLength(), this);
perkj600246e2016-05-04 11:26:51 -0700572
573 // Clear stats for disabled layers.
574 for (size_t i = encoder_settings->streams.size();
575 i < config_.rtp.ssrcs.size(); ++i) {
576 stats_proxy_.OnInactiveSsrc(config_.rtp.ssrcs[i]);
577 }
578
pbos14fe7082016-04-20 06:35:56 -0700579 if (config_.suspend_below_min_bitrate) {
Peter Boströmcd5c25c2016-04-21 16:48:08 +0200580 video_sender_->SuspendBelowMinBitrate();
pbos14fe7082016-04-20 06:35:56 -0700581 bitrate_allocator_->EnforceMinBitrate(false);
582 }
583 // We might've gotten new settings while configuring the encoder settings,
584 // restart from the top to see if that's the case before trying to encode
585 // a frame (which might correspond to the last frame size).
586 encoder_wakeup_event_.Set();
587 continue;
588 }
Peter Boströma4c76882016-03-03 16:29:02 +0100589
590 VideoFrame frame;
Per28a44562016-05-04 17:12:51 +0200591 if (input_.GetVideoFrame(&frame)) {
592 // TODO(perkj): |pre_encode_callback| is only used by tests. Tests should
593 // register as a sink to the VideoSource instead.
594 if (config_.pre_encode_callback) {
595 config_.pre_encode_callback->OnFrame(frame);
596 }
Peter Boströma4c76882016-03-03 16:29:02 +0100597 vie_encoder_.EncodeVideoFrame(frame);
Per28a44562016-05-04 17:12:51 +0200598 }
Peter Boströma4c76882016-03-03 16:29:02 +0100599 }
pbos14fe7082016-04-20 06:35:56 -0700600 vie_encoder_.DeRegisterExternalEncoder(config_.encoder_settings.payload_type);
Peter Boströma4c76882016-03-03 16:29:02 +0100601}
602
Peter Boström905f8e72016-03-02 16:59:56 +0100603void VideoSendStream::ReconfigureVideoEncoder(
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000604 const VideoEncoderConfig& config) {
pbos@webrtc.org50fe3592015-01-29 12:33:07 +0000605 TRACE_EVENT0("webrtc", "VideoSendStream::(Re)configureVideoEncoder");
pbos@webrtc.orgad3b5a52014-10-24 09:23:21 +0000606 LOG(LS_INFO) << "(Re)configureVideoEncoder: " << config.ToString();
pbos14fe7082016-04-20 06:35:56 -0700607 RTC_DCHECK_GE(config_.rtp.ssrcs.size(), config.streams.size());
608 VideoCodec video_codec = VideoEncoderConfigToVideoCodec(
609 config, config_.encoder_settings.payload_name,
610 config_.encoder_settings.payload_type);
611 {
612 rtc::CritScope lock(&encoder_settings_crit_);
613 pending_encoder_settings_ = rtc::Optional<EncoderSettings>(
perkjbc75d972016-05-02 06:31:25 -0700614 {video_codec, config.min_transmit_bitrate_bps, config.streams});
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000615 }
pbos14fe7082016-04-20 06:35:56 -0700616 encoder_wakeup_event_.Set();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000617}
618
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000619VideoSendStream::Stats VideoSendStream::GetStats() {
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000620 return stats_proxy_.GetStats();
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000621}
622
solenberge5269742015-09-08 05:13:22 -0700623void VideoSendStream::OveruseDetected() {
624 if (config_.overuse_callback)
625 config_.overuse_callback->OnLoadUpdate(LoadObserver::kOveruse);
626}
627
628void VideoSendStream::NormalUsage() {
629 if (config_.overuse_callback)
630 config_.overuse_callback->OnLoadUpdate(LoadObserver::kUnderuse);
631}
632
perkjbc75d972016-05-02 06:31:25 -0700633int32_t VideoSendStream::Encoded(const EncodedImage& encoded_image,
634 const CodecSpecificInfo* codec_specific_info,
635 const RTPFragmentationHeader* fragmentation) {
636 // |encoded_frame_proxy_| forwards frames to |config_.post_encode_callback|;
637 encoded_frame_proxy_.Encoded(encoded_image, codec_specific_info,
638 fragmentation);
perkj600246e2016-05-04 11:26:51 -0700639 int32_t return_value = payload_router_.Encoded(
640 encoded_image, codec_specific_info, fragmentation);
641
642 if (kEnableFrameRecording) {
643 int layer = codec_specific_info->codecType == kVideoCodecVP8
644 ? codec_specific_info->codecSpecific.VP8.simulcastIdx
645 : 0;
646 IvfFileWriter* file_writer;
647 {
648 if (file_writers_[layer] == nullptr) {
649 std::ostringstream oss;
650 oss << "send_bitstream_ssrc";
651 for (uint32_t ssrc : config_.rtp.ssrcs)
652 oss << "_" << ssrc;
653 oss << "_layer" << layer << ".ivf";
654 file_writers_[layer] =
655 IvfFileWriter::Open(oss.str(), codec_specific_info->codecType);
656 }
657 file_writer = file_writers_[layer].get();
658 }
659 if (file_writer) {
660 bool ok = file_writer->WriteFrame(encoded_image);
661 RTC_DCHECK(ok);
662 }
663 }
664
665 return return_value;
perkjbc75d972016-05-02 06:31:25 -0700666}
667
Per83d09102016-04-15 14:59:13 +0200668void VideoSendStream::ConfigureProtection() {
669 // Enable NACK, FEC or both.
670 const bool enable_protection_nack = config_.rtp.nack.rtp_history_ms > 0;
671 bool enable_protection_fec = config_.rtp.fec.red_payload_type != -1;
672 // Payload types without picture ID cannot determine that a stream is complete
673 // without retransmitting FEC, so using FEC + NACK for H.264 (for instance) is
674 // a waste of bandwidth since FEC packets still have to be transmitted. Note
675 // that this is not the case with FLEXFEC.
676 if (enable_protection_nack &&
677 !PayloadTypeSupportsSkippingFecPackets(
678 config_.encoder_settings.payload_name)) {
679 LOG(LS_WARNING) << "Transmitting payload type without picture ID using"
680 "NACK+FEC is a waste of bandwidth since FEC packets "
681 "also have to be retransmitted. Disabling FEC.";
682 enable_protection_fec = false;
683 }
684
685 // Set to valid uint8_ts to be castable later without signed overflows.
686 uint8_t payload_type_red = 0;
687 uint8_t payload_type_fec = 0;
688 // TODO(changbin): Should set RTX for RED mapping in RTP sender in future.
689 // Validate payload types. If either RED or FEC payload types are set then
690 // both should be. If FEC is enabled then they both have to be set.
691 if (enable_protection_fec || config_.rtp.fec.red_payload_type != -1 ||
692 config_.rtp.fec.ulpfec_payload_type != -1) {
693 RTC_DCHECK_GE(config_.rtp.fec.red_payload_type, 0);
694 RTC_DCHECK_GE(config_.rtp.fec.ulpfec_payload_type, 0);
695 RTC_DCHECK_LE(config_.rtp.fec.red_payload_type, 127);
696 RTC_DCHECK_LE(config_.rtp.fec.ulpfec_payload_type, 127);
697 payload_type_red = static_cast<uint8_t>(config_.rtp.fec.red_payload_type);
698 payload_type_fec =
699 static_cast<uint8_t>(config_.rtp.fec.ulpfec_payload_type);
700 } else {
701 // Payload types unset.
702 RTC_DCHECK_EQ(config_.rtp.fec.red_payload_type, -1);
703 RTC_DCHECK_EQ(config_.rtp.fec.ulpfec_payload_type, -1);
704 }
705
706 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
707 // Set NACK.
708 rtp_rtcp->SetStorePacketsStatus(
709 enable_protection_nack || congestion_controller_->pacer(),
710 kMinSendSidePacketHistorySize);
711 // Set FEC.
712 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
713 rtp_rtcp->SetGenericFECStatus(enable_protection_fec, payload_type_red,
714 payload_type_fec);
715 }
716 }
717
718 vie_encoder_.SetProtectionMethod(enable_protection_nack,
719 enable_protection_fec);
720}
721
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000722void VideoSendStream::ConfigureSsrcs() {
Peter Boström723ead82016-02-22 15:14:01 +0100723 // Configure regular SSRCs.
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000724 for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
725 uint32_t ssrc = config_.rtp.ssrcs[i];
Peter Boström723ead82016-02-22 15:14:01 +0100726 RtpRtcp* const rtp_rtcp = rtp_rtcp_modules_[i];
727 rtp_rtcp->SetSSRC(ssrc);
728
729 // Restore RTP state if previous existed.
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000730 RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
731 if (it != suspended_ssrcs_.end())
Per83d09102016-04-15 14:59:13 +0200732 rtp_rtcp->SetRtpState(it->second);
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000733 }
734
Peter Boström723ead82016-02-22 15:14:01 +0100735 // Set up RTX if available.
736 if (config_.rtp.rtx.ssrcs.empty())
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000737 return;
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000738
Peter Boström723ead82016-02-22 15:14:01 +0100739 // Configure RTX SSRCs.
henrikg91d6ede2015-09-17 00:24:34 -0700740 RTC_DCHECK_EQ(config_.rtp.rtx.ssrcs.size(), config_.rtp.ssrcs.size());
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000741 for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
742 uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
Peter Boström723ead82016-02-22 15:14:01 +0100743 RtpRtcp* const rtp_rtcp = rtp_rtcp_modules_[i];
744 rtp_rtcp->SetRtxSsrc(ssrc);
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000745 RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
746 if (it != suspended_ssrcs_.end())
Per83d09102016-04-15 14:59:13 +0200747 rtp_rtcp->SetRtxState(it->second);
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000748 }
749
Peter Boström723ead82016-02-22 15:14:01 +0100750 // Configure RTX payload types.
henrikg91d6ede2015-09-17 00:24:34 -0700751 RTC_DCHECK_GE(config_.rtp.rtx.payload_type, 0);
Peter Boström723ead82016-02-22 15:14:01 +0100752 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
753 rtp_rtcp->SetRtxSendPayloadType(config_.rtp.rtx.payload_type,
754 config_.encoder_settings.payload_type);
755 rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
756 }
Stefan Holmer10880012016-02-03 13:29:59 +0100757 if (config_.rtp.fec.red_payload_type != -1 &&
758 config_.rtp.fec.red_rtx_payload_type != -1) {
Peter Boström723ead82016-02-22 15:14:01 +0100759 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
760 rtp_rtcp->SetRtxSendPayloadType(config_.rtp.fec.red_rtx_payload_type,
761 config_.rtp.fec.red_payload_type);
762 }
Stefan Holmer10880012016-02-03 13:29:59 +0100763 }
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000764}
765
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000766std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
767 std::map<uint32_t, RtpState> rtp_states;
768 for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
769 uint32_t ssrc = config_.rtp.ssrcs[i];
Per83d09102016-04-15 14:59:13 +0200770 RTC_DCHECK_EQ(ssrc, rtp_rtcp_modules_[i]->SSRC());
771 rtp_states[ssrc] = rtp_rtcp_modules_[i]->GetRtpState();
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000772 }
773
774 for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
775 uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
Per83d09102016-04-15 14:59:13 +0200776 rtp_states[ssrc] = rtp_rtcp_modules_[i]->GetRtxState();
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000777 }
778
779 return rtp_states;
780}
781
mflodman0e7e2592015-11-12 21:02:42 -0800782int VideoSendStream::GetPaddingNeededBps() const {
Peter Boström8c66a002016-02-11 13:51:10 +0100783 return vie_encoder_.GetPaddingNeededBps();
mflodman0e7e2592015-11-12 21:02:42 -0800784}
mflodman86aabb22016-03-11 15:44:32 +0100785
786void VideoSendStream::OnBitrateUpdated(uint32_t bitrate_bps,
787 uint8_t fraction_loss,
788 int64_t rtt) {
perkjbc75d972016-05-02 06:31:25 -0700789 payload_router_.SetTargetSendBitrate(bitrate_bps);
mflodman86aabb22016-03-11 15:44:32 +0100790 vie_encoder_.OnBitrateUpdated(bitrate_bps, fraction_loss, rtt);
791}
792
Per83d09102016-04-15 14:59:13 +0200793int VideoSendStream::ProtectionRequest(const FecProtectionParams* delta_params,
794 const FecProtectionParams* key_params,
795 uint32_t* sent_video_rate_bps,
796 uint32_t* sent_nack_rate_bps,
797 uint32_t* sent_fec_rate_bps) {
798 *sent_video_rate_bps = 0;
799 *sent_nack_rate_bps = 0;
800 *sent_fec_rate_bps = 0;
801 for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
802 uint32_t not_used = 0;
803 uint32_t module_video_rate = 0;
804 uint32_t module_fec_rate = 0;
805 uint32_t module_nack_rate = 0;
806 rtp_rtcp->SetFecParameters(delta_params, key_params);
807 rtp_rtcp->BitrateSent(&not_used, &module_video_rate, &module_fec_rate,
808 &module_nack_rate);
809 *sent_video_rate_bps += module_video_rate;
810 *sent_nack_rate_bps += module_nack_rate;
811 *sent_fec_rate_bps += module_fec_rate;
812 }
813 return 0;
814}
815
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000816} // namespace internal
817} // namespace webrtc