blob: 881802afb1eb4ce9688e79b5ef39908154c730f8 [file] [log] [blame]
pbos@webrtc.org29d58392013-05-16 12:08:031/*
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:0111#include "webrtc/video/video_send_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:0312
pbos@webrtc.orgdde16f12014-08-05 23:35:4313#include <algorithm>
pbos@webrtc.org1e92b0a2014-05-15 09:35:0614#include <sstream>
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:5715#include <string>
pbos@webrtc.org29d58392013-05-16 12:08:0316#include <vector>
17
18#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
pbos@webrtc.org6ae48c62014-06-06 10:49:1919#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.org50fe3592015-01-29 12:33:0720#include "webrtc/system_wrappers/interface/trace_event.h"
pbos@webrtc.org29d58392013-05-16 12:08:0321#include "webrtc/video_engine/include/vie_base.h"
22#include "webrtc/video_engine/include/vie_capture.h"
23#include "webrtc/video_engine/include/vie_codec.h"
stefan@webrtc.org360e3762013-08-22 09:29:5624#include "webrtc/video_engine/include/vie_external_codec.h"
pbos@webrtc.orgfe1ef932013-10-21 10:34:4325#include "webrtc/video_engine/include/vie_image_process.h"
pbos@webrtc.org29d58392013-05-16 12:08:0326#include "webrtc/video_engine/include/vie_network.h"
27#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
pbos@webrtc.orgf577ae92014-03-19 08:43:5728#include "webrtc/video_engine/vie_defines.h"
pbos@webrtc.org16e03b72013-10-28 16:32:0129#include "webrtc/video_send_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:0330
31namespace webrtc {
pbos@webrtc.org1e92b0a2014-05-15 09:35:0632std::string
pbos@webrtc.org024e4d52014-05-15 10:03:2433VideoSendStream::Config::EncoderSettings::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:0634 std::stringstream ss;
35 ss << "{payload_name: " << payload_name;
36 ss << ", payload_type: " << payload_type;
pbos@webrtc.org32e85282015-01-15 10:09:3937 ss << ", encoder: " << (encoder != NULL ? "(VideoEncoder)" : "NULL");
pbos@webrtc.org1e92b0a2014-05-15 09:35:0638 ss << '}';
39 return ss.str();
40}
41
pbos@webrtc.org024e4d52014-05-15 10:03:2442std::string VideoSendStream::Config::Rtp::Rtx::ToString()
pbos@webrtc.org1e92b0a2014-05-15 09:35:0643 const {
44 std::stringstream ss;
pbos@webrtc.org32e85282015-01-15 10:09:3945 ss << "{ssrcs: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0646 for (size_t i = 0; i < ssrcs.size(); ++i) {
47 ss << ssrcs[i];
48 if (i != ssrcs.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:3949 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0650 }
pbos@webrtc.org32e85282015-01-15 10:09:3951 ss << ']';
andrew@webrtc.org8f27fcc2015-01-09 20:22:4652
pbos@webrtc.org1e92b0a2014-05-15 09:35:0653 ss << ", payload_type: " << payload_type;
54 ss << '}';
55 return ss.str();
56}
57
pbos@webrtc.org024e4d52014-05-15 10:03:2458std::string VideoSendStream::Config::Rtp::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:0659 std::stringstream ss;
pbos@webrtc.org32e85282015-01-15 10:09:3960 ss << "{ssrcs: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0661 for (size_t i = 0; i < ssrcs.size(); ++i) {
62 ss << ssrcs[i];
63 if (i != ssrcs.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:3964 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0665 }
pbos@webrtc.org32e85282015-01-15 10:09:3966 ss << ']';
pbos@webrtc.org1e92b0a2014-05-15 09:35:0667 ss << ", max_packet_size: " << max_packet_size;
pbos@webrtc.org32e85282015-01-15 10:09:3968 ss << ", extensions: [";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0669 for (size_t i = 0; i < extensions.size(); ++i) {
70 ss << extensions[i].ToString();
71 if (i != extensions.size() - 1)
pbos@webrtc.org32e85282015-01-15 10:09:3972 ss << ", ";
pbos@webrtc.org1e92b0a2014-05-15 09:35:0673 }
pbos@webrtc.org32e85282015-01-15 10:09:3974 ss << ']';
pbos@webrtc.org1e92b0a2014-05-15 09:35:0675
pbos@webrtc.org32e85282015-01-15 10:09:3976 ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
77 ss << ", fec: " << fec.ToString();
78 ss << ", rtx: " << rtx.ToString();
79 ss << ", c_name: " << c_name;
pbos@webrtc.org1e92b0a2014-05-15 09:35:0680 ss << '}';
81 return ss.str();
82}
83
pbos@webrtc.org024e4d52014-05-15 10:03:2484std::string VideoSendStream::Config::ToString() const {
pbos@webrtc.org1e92b0a2014-05-15 09:35:0685 std::stringstream ss;
86 ss << "{encoder_settings: " << encoder_settings.ToString();
87 ss << ", rtp: " << rtp.ToString();
pbos@webrtc.org32e85282015-01-15 10:09:3988 ss << ", pre_encode_callback: "
89 << (pre_encode_callback != NULL ? "(I420FrameCallback)" : "NULL");
90 ss << ", post_encode_callback: "
91 << (post_encode_callback != NULL ? "(EncodedFrameObserver)" : "NULL");
92 ss << "local_renderer: " << (local_renderer != NULL ? "(VideoRenderer)"
93 : "NULL");
94 ss << ", render_delay_ms: " << render_delay_ms;
95 ss << ", target_delay_ms: " << target_delay_ms;
96 ss << ", suspend_below_min_bitrate: " << (suspend_below_min_bitrate ? "on"
97 : "off");
pbos@webrtc.org1e92b0a2014-05-15 09:35:0698 ss << '}';
99 return ss.str();
100}
pbos@webrtc.org29d58392013-05-16 12:08:03101
pbos@webrtc.org024e4d52014-05-15 10:03:24102namespace internal {
pbos@webrtc.org2bb1bda2014-07-07 13:06:48103VideoSendStream::VideoSendStream(
104 newapi::Transport* transport,
105 CpuOveruseObserver* overuse_observer,
106 webrtc::VideoEngine* video_engine,
107 const VideoSendStream::Config& config,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25108 const VideoEncoderConfig& encoder_config,
pbos@webrtc.org2bb1bda2014-07-07 13:06:48109 const std::map<uint32_t, RtpState>& suspended_ssrcs,
110 int base_channel,
pbos@webrtc.org00873182014-11-25 14:03:34111 Call::Config::BitrateConfig bitrate_config)
pbos@webrtc.org64887612013-11-14 08:58:14112 : transport_adapter_(transport),
sprang@webrtc.org40709352013-11-26 11:41:59113 encoded_frame_proxy_(config.post_encode_callback),
pbos@webrtc.org64887612013-11-14 08:58:14114 config_(config),
pbos@webrtc.org00873182014-11-25 14:03:34115 bitrate_config_(bitrate_config),
pbos@webrtc.org2bb1bda2014-07-07 13:06:48116 suspended_ssrcs_(suspended_ssrcs),
mflodman@webrtc.orgf3973e82013-12-13 09:40:45117 external_codec_(NULL),
pbos@webrtc.orgde1429e2014-04-28 13:00:21118 channel_(-1),
pbos@webrtc.org00873182014-11-25 14:03:34119 use_config_bitrate_(true),
pbos@webrtc.org273a4142014-12-01 15:23:21120 stats_proxy_(Clock::GetRealTimeClock(), config) {
pbos@webrtc.org00873182014-11-25 14:03:34121 // Duplicate assert checking of bitrate config. These should be checked in
122 // Call but are added here for verbosity.
123 assert(bitrate_config.min_bitrate_bps >= 0);
124 assert(bitrate_config.start_bitrate_bps >= bitrate_config.min_bitrate_bps);
125 if (bitrate_config.max_bitrate_bps != -1)
126 assert(bitrate_config.max_bitrate_bps >= bitrate_config.start_bitrate_bps);
127
pbos@webrtc.org29d58392013-05-16 12:08:03128 video_engine_base_ = ViEBase::GetInterface(video_engine);
pbos@webrtc.org40367f92015-02-13 08:00:06129 video_engine_base_->CreateChannelWithoutDefaultEncoder(channel_,
130 base_channel);
pbos@webrtc.org29d58392013-05-16 12:08:03131 assert(channel_ != -1);
132
133 rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
134 assert(rtp_rtcp_ != NULL);
135
pbos@webrtc.org64887612013-11-14 08:58:14136 assert(config_.rtp.ssrcs.size() > 0);
pbos@webrtc.org29023282013-09-11 10:14:56137
138 for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
139 const std::string& extension = config_.rtp.extensions[i].name;
140 int id = config_.rtp.extensions[i].id;
pbos@webrtc.orgce90eff2013-11-20 11:48:56141 if (extension == RtpExtension::kTOffset) {
pbos@webrtc.org29023282013-09-11 10:14:56142 if (rtp_rtcp_->SetSendTimestampOffsetStatus(channel_, true, id) != 0)
143 abort();
pbos@webrtc.orgce90eff2013-11-20 11:48:56144 } else if (extension == RtpExtension::kAbsSendTime) {
pbos@webrtc.org5c678ea2013-09-11 19:00:39145 if (rtp_rtcp_->SetSendAbsoluteSendTimeStatus(channel_, true, id) != 0)
146 abort();
pbos@webrtc.org29023282013-09-11 10:14:56147 } else {
148 abort(); // Unsupported extension.
149 }
150 }
pbos@webrtc.org29d58392013-05-16 12:08:03151
mflodman@webrtc.org92c27932013-12-13 16:36:28152 rtp_rtcp_->SetRembStatus(channel_, true, false);
153
pbos@webrtc.org0e63e762013-09-20 11:56:26154 // Enable NACK, FEC or both.
155 if (config_.rtp.fec.red_payload_type != -1) {
156 assert(config_.rtp.fec.ulpfec_payload_type != -1);
157 if (config_.rtp.nack.rtp_history_ms > 0) {
158 rtp_rtcp_->SetHybridNACKFECStatus(
159 channel_,
160 true,
161 static_cast<unsigned char>(config_.rtp.fec.red_payload_type),
162 static_cast<unsigned char>(config_.rtp.fec.ulpfec_payload_type));
163 } else {
164 rtp_rtcp_->SetFECStatus(
165 channel_,
166 true,
167 static_cast<unsigned char>(config_.rtp.fec.red_payload_type),
168 static_cast<unsigned char>(config_.rtp.fec.ulpfec_payload_type));
169 }
170 } else {
171 rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
172 }
173
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09174 ConfigureSsrcs();
175
pbos@webrtc.org013d9942013-08-22 09:42:17176 char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength];
177 assert(config_.rtp.c_name.length() < ViERTP_RTCP::KMaxRTCPCNameLength);
178 strncpy(rtcp_cname, config_.rtp.c_name.c_str(), sizeof(rtcp_cname) - 1);
179 rtcp_cname[sizeof(rtcp_cname) - 1] = '\0';
180
181 rtp_rtcp_->SetRTCPCName(channel_, rtcp_cname);
182
pbos@webrtc.org29d58392013-05-16 12:08:03183 capture_ = ViECapture::GetInterface(video_engine);
184 capture_->AllocateExternalCaptureDevice(capture_id_, external_capture_);
185 capture_->ConnectCaptureDevice(capture_id_, channel_);
186
187 network_ = ViENetwork::GetInterface(video_engine);
188 assert(network_ != NULL);
189
pbos@webrtc.orge75a1bf2013-09-18 11:52:42190 network_->RegisterSendTransport(channel_, transport_adapter_);
sprang@webrtc.org25fce9a2013-10-16 13:29:14191 // 28 to match packet overhead in ModuleRtpRtcpImpl.
pbos@webrtc.org16e03b72013-10-28 16:32:01192 network_->SetMTU(channel_,
193 static_cast<unsigned int>(config_.rtp.max_packet_size + 28));
pbos@webrtc.org29d58392013-05-16 12:08:03194
pbos@webrtc.orgf577ae92014-03-19 08:43:57195 assert(config.encoder_settings.encoder != NULL);
196 assert(config.encoder_settings.payload_type >= 0);
197 assert(config.encoder_settings.payload_type <= 127);
198 external_codec_ = ViEExternalCodec::GetInterface(video_engine);
199 if (external_codec_->RegisterExternalSendCodec(
200 channel_,
201 config.encoder_settings.payload_type,
202 config.encoder_settings.encoder,
203 false) != 0) {
204 abort();
stefan@webrtc.org360e3762013-08-22 09:29:56205 }
206
pbos@webrtc.org29d58392013-05-16 12:08:03207 codec_ = ViECodec::GetInterface(video_engine);
pbos@webrtc.orgbbe0a852014-09-19 12:30:25208 if (!ReconfigureVideoEncoder(encoder_config))
pbos@webrtc.org29d58392013-05-16 12:08:03209 abort();
pbos@webrtc.orgfe1ef932013-10-21 10:34:43210
pbos@webrtc.orgf577ae92014-03-19 08:43:57211 if (overuse_observer)
212 video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer);
pbos@webrtc.org3e6e2712015-02-26 12:19:31213 // Registered regardless of monitoring, used for stats.
214 video_engine_base_->RegisterCpuOveruseMetricsObserver(channel_,
215 &stats_proxy_);
pbos@webrtc.orgf577ae92014-03-19 08:43:57216
stefan@webrtc.org168f23f2014-07-11 13:44:02217 video_engine_base_->RegisterSendSideDelayObserver(channel_, &stats_proxy_);
pbos@webrtc.org273a4142014-12-01 15:23:21218 video_engine_base_->RegisterSendStatisticsProxy(channel_, &stats_proxy_);
stefan@webrtc.org168f23f2014-07-11 13:44:02219
pbos@webrtc.orgfe1ef932013-10-21 10:34:43220 image_process_ = ViEImageProcess::GetInterface(video_engine);
221 image_process_->RegisterPreEncodeCallback(channel_,
222 config_.pre_encode_callback);
sprang@webrtc.org40709352013-11-26 11:41:59223 if (config_.post_encode_callback) {
224 image_process_->RegisterPostEncodeImageCallback(channel_,
225 &encoded_frame_proxy_);
226 }
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57227
pbos@webrtc.org6ae48c62014-06-06 10:49:19228 if (config_.suspend_below_min_bitrate)
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43229 codec_->SuspendBelowMinBitrate(channel_);
sprang@webrtc.orgccd42842014-01-07 09:54:34230
sprang@webrtc.orgccd42842014-01-07 09:54:34231 rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(channel_,
stefan@webrtc.org168f23f2014-07-11 13:44:02232 &stats_proxy_);
sprang@webrtc.orgccd42842014-01-07 09:54:34233 rtp_rtcp_->RegisterSendChannelRtpStatisticsCallback(channel_,
stefan@webrtc.org168f23f2014-07-11 13:44:02234 &stats_proxy_);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00235 rtp_rtcp_->RegisterRtcpPacketTypeCounterObserver(channel_, &stats_proxy_);
stefan@webrtc.org168f23f2014-07-11 13:44:02236 rtp_rtcp_->RegisterSendBitrateObserver(channel_, &stats_proxy_);
237 rtp_rtcp_->RegisterSendFrameCountObserver(channel_, &stats_proxy_);
sprang@webrtc.orgccd42842014-01-07 09:54:34238
stefan@webrtc.org168f23f2014-07-11 13:44:02239 codec_->RegisterEncoderObserver(channel_, stats_proxy_);
240 capture_->RegisterObserver(capture_id_, stats_proxy_);
pbos@webrtc.org29d58392013-05-16 12:08:03241}
242
243VideoSendStream::~VideoSendStream() {
sprang@webrtc.orgccd42842014-01-07 09:54:34244 capture_->DeregisterObserver(capture_id_);
245 codec_->DeregisterEncoderObserver(channel_);
246
stefan@webrtc.org168f23f2014-07-11 13:44:02247 rtp_rtcp_->DeregisterSendFrameCountObserver(channel_, &stats_proxy_);
248 rtp_rtcp_->DeregisterSendBitrateObserver(channel_, &stats_proxy_);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00249 rtp_rtcp_->RegisterRtcpPacketTypeCounterObserver(channel_, NULL);
sprang@webrtc.orgccd42842014-01-07 09:54:34250 rtp_rtcp_->DeregisterSendChannelRtpStatisticsCallback(channel_,
stefan@webrtc.org168f23f2014-07-11 13:44:02251 &stats_proxy_);
sprang@webrtc.orgccd42842014-01-07 09:54:34252 rtp_rtcp_->DeregisterSendChannelRtcpStatisticsCallback(channel_,
stefan@webrtc.org168f23f2014-07-11 13:44:02253 &stats_proxy_);
sprang@webrtc.orgccd42842014-01-07 09:54:34254
pbos@webrtc.orgfe1ef932013-10-21 10:34:43255 image_process_->DeRegisterPreEncodeCallback(channel_);
256
pbos@webrtc.org29d58392013-05-16 12:08:03257 network_->DeregisterSendTransport(channel_);
pbos@webrtc.org29d58392013-05-16 12:08:03258
259 capture_->DisconnectCaptureDevice(channel_);
260 capture_->ReleaseCaptureDevice(capture_id_);
261
pbos@webrtc.orgf577ae92014-03-19 08:43:57262 external_codec_->DeRegisterExternalSendCodec(
263 channel_, config_.encoder_settings.payload_type);
stefan@webrtc.org360e3762013-08-22 09:29:56264
pbos@webrtc.orgfe1ef932013-10-21 10:34:43265 video_engine_base_->DeleteChannel(channel_);
266
267 image_process_->Release();
pbos@webrtc.org29d58392013-05-16 12:08:03268 video_engine_base_->Release();
269 capture_->Release();
270 codec_->Release();
stefan@webrtc.org360e3762013-08-22 09:29:56271 if (external_codec_)
272 external_codec_->Release();
pbos@webrtc.org29d58392013-05-16 12:08:03273 network_->Release();
274 rtp_rtcp_->Release();
275}
276
pbos@webrtc.org724947b2013-12-11 16:26:16277void VideoSendStream::SwapFrame(I420VideoFrame* frame) {
pbos@webrtc.org724947b2013-12-11 16:26:16278 // TODO(pbos): Local rendering should not be done on the capture thread.
279 if (config_.local_renderer != NULL)
pbos@webrtc.org1566ee22014-05-23 13:03:45280 config_.local_renderer->RenderFrame(*frame, 0);
pbos@webrtc.org29d58392013-05-16 12:08:03281
pbos@webrtc.org1566ee22014-05-23 13:03:45282 external_capture_->SwapFrame(frame);
pbos@webrtc.org29d58392013-05-16 12:08:03283}
284
pbos@webrtc.org74fa4892013-08-23 09:19:30285VideoSendStreamInput* VideoSendStream::Input() { return this; }
pbos@webrtc.org29d58392013-05-16 12:08:03286
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21287void VideoSendStream::Start() {
sprang@webrtc.orgd9b95602014-01-27 13:03:02288 transport_adapter_.Enable();
pbos@webrtc.orgf777cf22014-01-10 18:47:32289 video_engine_base_->StartSend(channel_);
290 video_engine_base_->StartReceive(channel_);
pbos@webrtc.org29d58392013-05-16 12:08:03291}
292
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21293void VideoSendStream::Stop() {
pbos@webrtc.orgf777cf22014-01-10 18:47:32294 video_engine_base_->StopSend(channel_);
295 video_engine_base_->StopReceive(channel_);
sprang@webrtc.orgd9b95602014-01-27 13:03:02296 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03297}
298
pbos@webrtc.orgf577ae92014-03-19 08:43:57299bool VideoSendStream::ReconfigureVideoEncoder(
pbos@webrtc.orgbbe0a852014-09-19 12:30:25300 const VideoEncoderConfig& config) {
pbos@webrtc.org50fe3592015-01-29 12:33:07301 TRACE_EVENT0("webrtc", "VideoSendStream::(Re)configureVideoEncoder");
pbos@webrtc.orgad3b5a52014-10-24 09:23:21302 LOG(LS_INFO) << "(Re)configureVideoEncoder: " << config.ToString();
pbos@webrtc.orgbbe0a852014-09-19 12:30:25303 const std::vector<VideoStream>& streams = config.streams;
pbos@webrtc.orgf577ae92014-03-19 08:43:57304 assert(!streams.empty());
305 assert(config_.rtp.ssrcs.size() >= streams.size());
pbos@webrtc.org64887612013-11-14 08:58:14306
pbos@webrtc.orgf577ae92014-03-19 08:43:57307 VideoCodec video_codec;
308 memset(&video_codec, 0, sizeof(video_codec));
stefan@webrtc.org79c33592014-08-06 09:24:53309 if (config_.encoder_settings.payload_name == "VP8") {
310 video_codec.codecType = kVideoCodecVP8;
marpan@webrtc.org5b883172014-11-01 06:10:48311 } else if (config_.encoder_settings.payload_name == "VP9") {
312 video_codec.codecType = kVideoCodecVP9;
stefan@webrtc.org79c33592014-08-06 09:24:53313 } else if (config_.encoder_settings.payload_name == "H264") {
314 video_codec.codecType = kVideoCodecH264;
315 } else {
316 video_codec.codecType = kVideoCodecGeneric;
317 }
pbos@webrtc.orgb7ed7792014-10-31 13:08:10318
pbos@webrtc.orgbbe0a852014-09-19 12:30:25319 switch (config.content_type) {
320 case VideoEncoderConfig::kRealtimeVideo:
321 video_codec.mode = kRealtimeVideo;
322 break;
323 case VideoEncoderConfig::kScreenshare:
324 video_codec.mode = kScreensharing;
pbos@webrtc.orgb7ed7792014-10-31 13:08:10325 if (config.streams.size() == 1 &&
326 config.streams[0].temporal_layer_thresholds_bps.size() == 1) {
327 video_codec.targetBitrate =
328 config.streams[0].temporal_layer_thresholds_bps[0] / 1000;
329 }
pbos@webrtc.orgbbe0a852014-09-19 12:30:25330 break;
331 }
pbos@webrtc.orgf577ae92014-03-19 08:43:57332
333 if (video_codec.codecType == kVideoCodecVP8) {
pbos@webrtc.org6cd6ba82014-09-18 12:42:28334 video_codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
marpan@webrtc.org5b883172014-11-01 06:10:48335 } else if (video_codec.codecType == kVideoCodecVP9) {
336 video_codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
stefan@webrtc.org79c33592014-08-06 09:24:53337 } else if (video_codec.codecType == kVideoCodecH264) {
pbos@webrtc.org6cd6ba82014-09-18 12:42:28338 video_codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
pbos@webrtc.orgf577ae92014-03-19 08:43:57339 }
340
pbos@webrtc.org91f17522014-07-10 10:13:37341 if (video_codec.codecType == kVideoCodecVP8) {
pbos@webrtc.orgbbe0a852014-09-19 12:30:25342 if (config.encoder_specific_settings != NULL) {
343 video_codec.codecSpecific.VP8 = *reinterpret_cast<const VideoCodecVP8*>(
344 config.encoder_specific_settings);
pbos@webrtc.org91f17522014-07-10 10:13:37345 }
pbos@webrtc.org759982d2014-09-22 09:32:46346 video_codec.codecSpecific.VP8.numberOfTemporalLayers =
pbos@webrtc.orgb7ed7792014-10-31 13:08:10347 static_cast<unsigned char>(
348 streams.back().temporal_layer_thresholds_bps.size() + 1);
pbos@webrtc.org91f17522014-07-10 10:13:37349 } else {
350 // TODO(pbos): Support encoder_settings codec-agnostically.
pbos@webrtc.orgbbe0a852014-09-19 12:30:25351 assert(config.encoder_specific_settings == NULL);
pbos@webrtc.org91f17522014-07-10 10:13:37352 }
353
pbos@webrtc.orgf577ae92014-03-19 08:43:57354 strncpy(video_codec.plName,
355 config_.encoder_settings.payload_name.c_str(),
356 kPayloadNameSize - 1);
357 video_codec.plName[kPayloadNameSize - 1] = '\0';
358 video_codec.plType = config_.encoder_settings.payload_type;
359 video_codec.numberOfSimulcastStreams =
360 static_cast<unsigned char>(streams.size());
361 video_codec.minBitrate = streams[0].min_bitrate_bps / 1000;
362 assert(streams.size() <= kMaxSimulcastStreams);
363 for (size_t i = 0; i < streams.size(); ++i) {
364 SimulcastStream* sim_stream = &video_codec.simulcastStream[i];
365 assert(streams[i].width > 0);
366 assert(streams[i].height > 0);
367 assert(streams[i].max_framerate > 0);
368 // Different framerates not supported per stream at the moment.
369 assert(streams[i].max_framerate == streams[0].max_framerate);
370 assert(streams[i].min_bitrate_bps >= 0);
371 assert(streams[i].target_bitrate_bps >= streams[i].min_bitrate_bps);
372 assert(streams[i].max_bitrate_bps >= streams[i].target_bitrate_bps);
373 assert(streams[i].max_qp >= 0);
374
375 sim_stream->width = static_cast<unsigned short>(streams[i].width);
376 sim_stream->height = static_cast<unsigned short>(streams[i].height);
377 sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000;
378 sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000;
379 sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000;
380 sim_stream->qpMax = streams[i].max_qp;
pbos@webrtc.orgb7ed7792014-10-31 13:08:10381 sim_stream->numberOfTemporalLayers = static_cast<unsigned char>(
382 streams[i].temporal_layer_thresholds_bps.size() + 1);
pbos@webrtc.orgf577ae92014-03-19 08:43:57383
384 video_codec.width = std::max(video_codec.width,
385 static_cast<unsigned short>(streams[i].width));
386 video_codec.height = std::max(
387 video_codec.height, static_cast<unsigned short>(streams[i].height));
388 video_codec.minBitrate =
389 std::min(video_codec.minBitrate,
390 static_cast<unsigned int>(streams[i].min_bitrate_bps / 1000));
391 video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000;
392 video_codec.qpMax = std::max(video_codec.qpMax,
393 static_cast<unsigned int>(streams[i].max_qp));
394 }
pbos@webrtc.org00873182014-11-25 14:03:34395 // Clamp bitrates to the bitrate config.
396 if (video_codec.minBitrate <
397 static_cast<unsigned int>(bitrate_config_.min_bitrate_bps / 1000)) {
398 video_codec.minBitrate = bitrate_config_.min_bitrate_bps / 1000;
399 }
400 if (bitrate_config_.max_bitrate_bps != -1 &&
401 video_codec.maxBitrate >
402 static_cast<unsigned int>(bitrate_config_.max_bitrate_bps / 1000)) {
403 video_codec.maxBitrate = bitrate_config_.max_bitrate_bps / 1000;
404 }
pbos@webrtc.org32452b22014-10-22 12:15:24405 unsigned int start_bitrate_bps;
406 if (codec_->GetCodecTargetBitrate(channel_, &start_bitrate_bps) != 0 ||
pbos@webrtc.org00873182014-11-25 14:03:34407 use_config_bitrate_) {
408 start_bitrate_bps = bitrate_config_.start_bitrate_bps;
pbos@webrtc.org32452b22014-10-22 12:15:24409 }
mflodman@webrtc.orgeb16b812014-06-16 08:57:39410 video_codec.startBitrate =
pbos@webrtc.org32452b22014-10-22 12:15:24411 static_cast<unsigned int>(start_bitrate_bps) / 1000;
pbos@webrtc.orgf577ae92014-03-19 08:43:57412
413 if (video_codec.minBitrate < kViEMinCodecBitrate)
414 video_codec.minBitrate = kViEMinCodecBitrate;
415 if (video_codec.maxBitrate < kViEMinCodecBitrate)
416 video_codec.maxBitrate = kViEMinCodecBitrate;
mflodman@webrtc.orgeb16b812014-06-16 08:57:39417 if (video_codec.startBitrate < video_codec.minBitrate)
418 video_codec.startBitrate = video_codec.minBitrate;
419 if (video_codec.startBitrate > video_codec.maxBitrate)
420 video_codec.startBitrate = video_codec.maxBitrate;
pbos@webrtc.orgf577ae92014-03-19 08:43:57421
422 if (video_codec.startBitrate < video_codec.minBitrate)
423 video_codec.startBitrate = video_codec.minBitrate;
424 if (video_codec.startBitrate > video_codec.maxBitrate)
425 video_codec.startBitrate = video_codec.maxBitrate;
426
pbos@webrtc.org6ae48c62014-06-06 10:49:19427 assert(streams[0].max_framerate > 0);
428 video_codec.maxFramerate = streams[0].max_framerate;
pbos@webrtc.orgf577ae92014-03-19 08:43:57429
pbos@webrtc.org32452b22014-10-22 12:15:24430 if (codec_->SetSendCodec(channel_, video_codec) != 0)
431 return false;
432
pbos@webrtc.orgad3b5a52014-10-24 09:23:21433 assert(config.min_transmit_bitrate_bps >= 0);
434 rtp_rtcp_->SetMinTransmitBitrate(channel_,
435 config.min_transmit_bitrate_bps / 1000);
436
pbos@webrtc.org00873182014-11-25 14:03:34437 encoder_config_ = config;
438 use_config_bitrate_ = false;
pbos@webrtc.org32452b22014-10-22 12:15:24439 return true;
pbos@webrtc.org29d58392013-05-16 12:08:03440}
441
pbos@webrtc.orgbbb07e62013-08-05 12:01:36442bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
pkasting@chromium.org4591fbd2014-11-20 22:28:14443 return network_->ReceivedRTCPPacket(channel_, packet, length) == 0;
pbos@webrtc.orgbbb07e62013-08-05 12:01:36444}
sprang@webrtc.orgccd42842014-01-07 09:54:34445
pbos@webrtc.org273a4142014-12-01 15:23:21446VideoSendStream::Stats VideoSendStream::GetStats() {
stefan@webrtc.org168f23f2014-07-11 13:44:02447 return stats_proxy_.GetStats();
sprang@webrtc.orgccd42842014-01-07 09:54:34448}
449
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09450void VideoSendStream::ConfigureSsrcs() {
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00451 rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.ssrcs.front());
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09452 for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
453 uint32_t ssrc = config_.rtp.ssrcs[i];
454 rtp_rtcp_->SetLocalSSRC(
455 channel_, ssrc, kViEStreamTypeNormal, static_cast<unsigned char>(i));
pbos@webrtc.org2bb1bda2014-07-07 13:06:48456 RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
457 if (it != suspended_ssrcs_.end())
458 rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09459 }
460
461 if (config_.rtp.rtx.ssrcs.empty()) {
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09462 return;
463 }
464
465 // Set up RTX.
466 assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
pbos@webrtc.org2bb1bda2014-07-07 13:06:48467 for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
468 uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09469 rtp_rtcp_->SetLocalSSRC(channel_,
470 config_.rtp.rtx.ssrcs[i],
471 kViEStreamTypeRtx,
472 static_cast<unsigned char>(i));
pbos@webrtc.org2bb1bda2014-07-07 13:06:48473 RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
474 if (it != suspended_ssrcs_.end())
475 rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09476 }
477
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09478 assert(config_.rtp.rtx.payload_type >= 0);
andrew@webrtc.org8f27fcc2015-01-09 20:22:46479 rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09480}
481
pbos@webrtc.org2bb1bda2014-07-07 13:06:48482std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
483 std::map<uint32_t, RtpState> rtp_states;
484 for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
485 uint32_t ssrc = config_.rtp.ssrcs[i];
486 rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
487 }
488
489 for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
490 uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
491 rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
492 }
493
494 return rtp_states;
495}
496
pbos@webrtc.org00873182014-11-25 14:03:34497void VideoSendStream::SetBitrateConfig(
498 const Call::Config::BitrateConfig& bitrate_config) {
499 int last_start_bitrate_bps = bitrate_config_.start_bitrate_bps;
500 bitrate_config_ = bitrate_config;
501 if (bitrate_config_.start_bitrate_bps <= 0) {
502 bitrate_config_.start_bitrate_bps = last_start_bitrate_bps;
503 } else {
504 // Override start bitrate with bitrate from config.
505 use_config_bitrate_ = true;
506 }
507 ReconfigureVideoEncoder(encoder_config_);
508}
509
pbos@webrtc.org26c0c412014-09-03 16:17:12510void VideoSendStream::SignalNetworkState(Call::NetworkState state) {
511 // When network goes up, enable RTCP status before setting transmission state.
512 // When it goes down, disable RTCP afterwards. This ensures that any packets
513 // sent due to the network state changed will not be dropped.
514 if (state == Call::kNetworkUp)
515 rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
516 network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp);
517 if (state == Call::kNetworkDown)
518 rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
519}
520
pkasting@chromium.org16825b12015-01-12 21:51:21521int64_t VideoSendStream::GetPacerQueuingDelayMs() const {
522 int64_t pacer_delay_ms = 0;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29523 if (rtp_rtcp_->GetPacerQueuingDelayMs(channel_, &pacer_delay_ms) != 0) {
524 return 0;
525 }
526 return pacer_delay_ms;
527}
pbos@webrtc.org2b19f062014-12-11 13:26:09528
pkasting@chromium.org16825b12015-01-12 21:51:21529int64_t VideoSendStream::GetRtt() const {
pbos@webrtc.org2b19f062014-12-11 13:26:09530 webrtc::RtcpStatistics rtcp_stats;
pkasting@chromium.org16825b12015-01-12 21:51:21531 int64_t rtt_ms;
pbos@webrtc.org2b19f062014-12-11 13:26:09532 if (rtp_rtcp_->GetSendChannelRtcpStatistics(channel_, rtcp_stats, rtt_ms) ==
533 0) {
534 return rtt_ms;
535 }
536 return -1;
537}
pbos@webrtc.org29d58392013-05-16 12:08:03538} // namespace internal
539} // namespace webrtc