blob: 5583c7585b3dd2fcbab64189d79f385337032394 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org07b45a52012-02-02 08:37:48 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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.orgf5d4cb12013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_encoder.h"
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
14
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000015#include <algorithm>
niklase@google.com470e71d2011-07-07 08:21:25 +000016
sprang@webrtc.org40709352013-11-26 11:41:59 +000017#include "webrtc/common_video/interface/video_image.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000018#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/modules/pacing/include/paced_sender.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
23#include "webrtc/modules/video_coding/main/interface/video_coding.h"
24#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
sprang@webrtc.org40709352013-11-26 11:41:59 +000025#include "webrtc/modules/video_coding/main/source/encoded_frame.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000026#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/logging.h"
28#include "webrtc/system_wrappers/interface/tick_util.h"
29#include "webrtc/system_wrappers/interface/trace.h"
30#include "webrtc/system_wrappers/interface/trace_event.h"
31#include "webrtc/video_engine/include/vie_codec.h"
32#include "webrtc/video_engine/include/vie_image_process.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000033#include "webrtc/frame_callback.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000034#include "webrtc/video_engine/vie_defines.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000035
niklase@google.com470e71d2011-07-07 08:21:25 +000036namespace webrtc {
37
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000038// Pace in kbits/s until we receive first estimate.
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +000039static const int kInitialPace = 2000;
pwestin@webrtc.org91563e42013-04-25 22:20:08 +000040
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +000041// Pacing-rate relative to our target send rate.
42// Multiplicative factor that is applied to the target bitrate to calculate the
43// number of bytes that can be transmitted per interval.
44// Increasing this factor will result in lower delays in cases of bitrate
45// overshoots from the encoder.
46static const float kPaceMultiplier = 2.5f;
47
48// Margin on when we pause the encoder when the pacing buffer overflows relative
49// to the configured buffer delay.
50static const float kEncoderPausePacerMargin = 2.0f;
51
pwestin@webrtc.org91563e42013-04-25 22:20:08 +000052// Don't stop the encoder unless the delay is above this configured value.
53static const int kMinPacingDelayMs = 200;
54
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +000055// Allow packets to be transmitted in up to 2 times max video bitrate if the
56// bandwidth estimate allows it.
57// TODO(holmer): Expose transmission start, min and max bitrates in the
58// VideoEngine API and remove the kTransmissionMaxBitrateMultiplier.
59static const int kTransmissionMaxBitrateMultiplier = 2;
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +000060
stefan@webrtc.org3e005052013-10-18 15:05:29 +000061static const float kStopPaddingThresholdMs = 2000;
62
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +000063std::vector<uint32_t> AllocateStreamBitrates(
64 uint32_t total_bitrate,
65 const SimulcastStream* stream_configs,
66 size_t number_of_streams) {
67 if (number_of_streams == 0) {
68 std::vector<uint32_t> stream_bitrates(1, 0);
69 stream_bitrates[0] = total_bitrate;
70 return stream_bitrates;
71 }
72 std::vector<uint32_t> stream_bitrates(number_of_streams, 0);
73 uint32_t bitrate_remainder = total_bitrate;
74 for (size_t i = 0; i < stream_bitrates.size() && bitrate_remainder > 0; ++i) {
75 if (stream_configs[i].maxBitrate * 1000 > bitrate_remainder) {
76 stream_bitrates[i] = bitrate_remainder;
77 } else {
78 stream_bitrates[i] = stream_configs[i].maxBitrate * 1000;
79 }
80 bitrate_remainder -= stream_bitrates[i];
81 }
82 return stream_bitrates;
83}
84
stefan@webrtc.org439be292012-02-16 14:45:37 +000085class QMVideoSettingsCallback : public VCMQMSettingsCallback {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000086 public:
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +000087 explicit QMVideoSettingsCallback(VideoProcessingModule* vpm);
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000088
stefan@webrtc.org439be292012-02-16 14:45:37 +000089 ~QMVideoSettingsCallback();
niklase@google.com470e71d2011-07-07 08:21:25 +000090
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000091 // Update VPM with QM (quality modes: frame size & frame rate) settings.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +000092 int32_t SetVideoQMSettings(const uint32_t frame_rate,
93 const uint32_t width,
94 const uint32_t height);
niklase@google.com470e71d2011-07-07 08:21:25 +000095
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000096 private:
97 VideoProcessingModule* vpm_;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +000098};
niklase@google.com470e71d2011-07-07 08:21:25 +000099
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000100class ViEBitrateObserver : public BitrateObserver {
101 public:
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000102 explicit ViEBitrateObserver(ViEEncoder* owner)
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000103 : owner_(owner) {
104 }
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +0000105 virtual ~ViEBitrateObserver() {}
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000106 // Implements BitrateObserver.
107 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
108 const uint8_t fraction_lost,
109 const uint32_t rtt) {
110 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
111 }
112 private:
113 ViEEncoder* owner_;
114};
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000116class ViEPacedSenderCallback : public PacedSender::Callback {
117 public:
118 explicit ViEPacedSenderCallback(ViEEncoder* owner)
119 : owner_(owner) {
120 }
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +0000121 virtual ~ViEPacedSenderCallback() {}
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000122 virtual bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000123 int64_t capture_time_ms, bool retransmission) {
124 return owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms,
125 retransmission);
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000126 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000127 virtual int TimeToSendPadding(int bytes) {
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000128 return owner_->TimeToSendPadding(bytes);
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000129 }
130 private:
131 ViEEncoder* owner_;
132};
133
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000134ViEEncoder::ViEEncoder(int32_t engine_id,
135 int32_t channel_id,
136 uint32_t number_of_cores,
andresp@webrtc.org7707d062013-05-13 10:50:50 +0000137 const Config& config,
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000138 ProcessThread& module_process_thread,
139 BitrateController* bitrate_controller)
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000140 : engine_id_(engine_id),
141 channel_id_(channel_id),
142 number_of_cores_(number_of_cores),
143 vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
144 channel_id))),
145 vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
146 channel_id))),
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000147 callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
148 data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000149 bitrate_controller_(bitrate_controller),
stefan@webrtc.org3e005052013-10-18 15:05:29 +0000150 time_of_last_incoming_frame_ms_(0),
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000151 send_padding_(false),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000152 min_transmit_bitrate_kbps_(0),
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000153 target_delay_ms_(0),
154 network_is_transmitting_(true),
155 encoder_paused_(false),
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000156 encoder_paused_and_dropped_frame_(false),
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000157 fec_enabled_(false),
158 nack_enabled_(false),
159 codec_observer_(NULL),
160 effect_filter_(NULL),
161 module_process_thread_(module_process_thread),
162 has_received_sli_(false),
163 picture_id_sli_(0),
164 has_received_rpsi_(false),
165 picture_id_rpsi_(0),
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +0000166 qm_callback_(NULL),
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000167 video_suspended_(false),
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +0000168 pre_encode_callback_(NULL) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000169 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
170 ViEId(engine_id, channel_id),
171 "%s(engine_id: %d) 0x%p - Constructor", __FUNCTION__, engine_id,
172 this);
pwestin@webrtc.orgce330352012-04-12 06:59:14 +0000173
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000174 RtpRtcp::Configuration configuration;
175 configuration.id = ViEModuleId(engine_id_, channel_id_);
176 configuration.audio = false; // Video.
177
178 default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000179 bitrate_observer_.reset(new ViEBitrateObserver(this));
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000180 pacing_callback_.reset(new ViEPacedSenderCallback(this));
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000181 paced_sender_.reset(
182 new PacedSender(pacing_callback_.get(), kInitialPace, kPaceMultiplier));
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000183}
184
185bool ViEEncoder::Init() {
186 if (vcm_.InitializeSender() != 0) {
187 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
188 ViEId(engine_id_, channel_id_),
189 "%s InitializeSender failure", __FUNCTION__);
190 return false;
191 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000192 vpm_.EnableTemporalDecimation(true);
193
194 // Enable/disable content analysis: off by default for now.
195 vpm_.EnableContentAnalysis(false);
196
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000197 if (module_process_thread_.RegisterModule(&vcm_) != 0 ||
198 module_process_thread_.RegisterModule(default_rtp_rtcp_.get()) != 0 ||
199 module_process_thread_.RegisterModule(paced_sender_.get()) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000200 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
201 ViEId(engine_id_, channel_id_),
202 "%s RegisterModule failure", __FUNCTION__);
203 return false;
204 }
stefan@webrtc.org97845122012-04-13 07:47:05 +0000205 if (qm_callback_) {
206 delete qm_callback_;
207 }
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +0000208 qm_callback_ = new QMVideoSettingsCallback(&vpm_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
210#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000211 VideoCodec video_codec;
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000212 if (vcm_.Codec(webrtc::kVideoCodecVP8, &video_codec) != VCM_OK) {
213 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
214 ViEId(engine_id_, channel_id_),
215 "%s Codec failure", __FUNCTION__);
216 return false;
217 }
stefan@webrtc.orgae2563a2014-02-13 13:48:38 +0000218 {
219 CriticalSectionScoped cs(data_cs_.get());
220 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
221 }
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000222 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000223 default_rtp_rtcp_->MaxDataPayloadLength()) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000224 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
225 ViEId(engine_id_, channel_id_),
226 "%s RegisterSendCodec failure", __FUNCTION__);
227 return false;
228 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000229 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000230 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
231 ViEId(engine_id_, channel_id_),
232 "%s RegisterSendPayload failure", __FUNCTION__);
233 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000234 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000235#else
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000236 VideoCodec video_codec;
237 if (vcm_.Codec(webrtc::kVideoCodecI420, &video_codec) == VCM_OK) {
stefan@webrtc.orgae2563a2014-02-13 13:48:38 +0000238 {
239 CriticalSectionScoped cs(data_cs_.get());
240 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
241 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000242 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000243 default_rtp_rtcp_->MaxDataPayloadLength());
244 default_rtp_rtcp_->RegisterSendPayload(video_codec);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000245 } else {
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000246 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000247 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000248#endif
249
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000250 if (vcm_.RegisterTransportCallback(this) != 0) {
251 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
252 ViEId(engine_id_, channel_id_),
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000253 "ViEEncoder: VCM::RegisterTransportCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000254 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000255 }
256 if (vcm_.RegisterSendStatisticsCallback(this) != 0) {
257 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
258 ViEId(engine_id_, channel_id_),
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000259 "ViEEncoder: VCM::RegisterSendStatisticsCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000260 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000261 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000262 if (vcm_.RegisterVideoQMCallback(qm_callback_) != 0) {
263 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
264 ViEId(engine_id_, channel_id_),
265 "VCM::RegisterQMCallback failure");
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000266 return false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000267 }
wu@webrtc.org5d8c1022012-04-10 16:54:05 +0000268 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269}
270
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000271ViEEncoder::~ViEEncoder() {
272 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
273 ViEId(engine_id_, channel_id_),
274 "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
stefan@webrtc.orgbf415082012-11-29 09:18:53 +0000275 if (bitrate_controller_) {
276 bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
277 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000278 module_process_thread_.DeRegisterModule(&vcm_);
279 module_process_thread_.DeRegisterModule(&vpm_);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000280 module_process_thread_.DeRegisterModule(default_rtp_rtcp_.get());
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000281 module_process_thread_.DeRegisterModule(paced_sender_.get());
mflodman@webrtc.org66480932013-03-01 14:51:23 +0000282 VideoCodingModule::Destroy(&vcm_);
283 VideoProcessingModule::Destroy(&vpm_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000284 delete qm_callback_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
mflodman@webrtc.org9ec883e2012-03-05 17:12:41 +0000287int ViEEncoder::Owner() const {
288 return channel_id_;
289}
290
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000291void ViEEncoder::SetNetworkTransmissionState(bool is_transmitting) {
292 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
293 ViEId(engine_id_, channel_id_),
294 "%s(%s)", __FUNCTION__,
295 is_transmitting ? "transmitting" : "not transmitting");
296 {
297 CriticalSectionScoped cs(data_cs_.get());
298 network_is_transmitting_ = is_transmitting;
299 }
300 if (is_transmitting) {
301 paced_sender_->Resume();
302 } else {
303 paced_sender_->Pause();
304 }
305}
306
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000307void ViEEncoder::Pause() {
308 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
309 ViEId(engine_id_, channel_id_),
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 "%s", __FUNCTION__);
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000311 CriticalSectionScoped cs(data_cs_.get());
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000312 encoder_paused_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000313}
314
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000315void ViEEncoder::Restart() {
316 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
317 ViEId(engine_id_, channel_id_),
318 "%s", __FUNCTION__);
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000319 CriticalSectionScoped cs(data_cs_.get());
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000320 encoder_paused_ = false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000321}
322
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000323uint8_t ViEEncoder::NumberOfCodecs() {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000324 return vcm_.NumberOfCodecs();
325}
326
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000327int32_t ViEEncoder::GetCodec(uint8_t list_index, VideoCodec* video_codec) {
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000328 if (vcm_.Codec(list_index, video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000329 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
330 ViEId(engine_id_, channel_id_), "%s: Could not get codec",
331 __FUNCTION__);
332 return -1;
333 }
334 return 0;
335}
336
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000337int32_t ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
338 uint8_t pl_type,
339 bool internal_source) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000340 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
341 ViEId(engine_id_, channel_id_), "%s: pltype %u", __FUNCTION__,
342 pl_type);
343
344 if (encoder == NULL)
345 return -1;
346
stefan@webrtc.orgfcd85852013-01-09 08:35:40 +0000347 if (vcm_.RegisterExternalEncoder(encoder, pl_type, internal_source) !=
348 VCM_OK) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000349 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
350 ViEId(engine_id_, channel_id_),
351 "Could not register external encoder");
352 return -1;
353 }
354 return 0;
355}
356
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000357int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000358 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
359 ViEId(engine_id_, channel_id_),
360 "%s: pltype %u", __FUNCTION__, pl_type);
361
362 webrtc::VideoCodec current_send_codec;
363 if (vcm_.SendCodec(&current_send_codec) == VCM_OK) {
stefan@webrtc.org3d0b0d62013-03-19 10:04:57 +0000364 uint32_t current_bitrate_bps = 0;
365 if (vcm_.Bitrate(&current_bitrate_bps) != 0) {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000366 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
367 ViEId(engine_id_, channel_id_),
368 "Failed to get the current encoder target bitrate.");
369 }
stefan@webrtc.org3d0b0d62013-03-19 10:04:57 +0000370 current_send_codec.startBitrate = (current_bitrate_bps + 500) / 1000;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000371 }
372
373 if (vcm_.RegisterExternalEncoder(NULL, pl_type) != VCM_OK) {
374 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
375 ViEId(engine_id_, channel_id_),
376 "Could not deregister external encoder");
377 return -1;
378 }
379
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000380 // If the external encoder is the current send codec, use vcm internal
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000381 // encoder.
382 if (current_send_codec.plType == pl_type) {
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000383 uint16_t max_data_payload_length =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000384 default_rtp_rtcp_->MaxDataPayloadLength();
stefan@webrtc.orgae2563a2014-02-13 13:48:38 +0000385 {
386 CriticalSectionScoped cs(data_cs_.get());
387 send_padding_ = current_send_codec.numberOfSimulcastStreams > 1;
388 }
fischman@webrtc.org64e04052014-03-07 18:00:05 +0000389 // TODO(mflodman): Unfortunately the VideoCodec that VCM has cached a
390 // raw pointer to an |extra_options| that's long gone. Clearing it here is
391 // a hack to prevent the following code from crashing. This should be fixed
392 // for realz. https://code.google.com/p/chromium/issues/detail?id=348222
393 current_send_codec.extra_options = NULL;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000394 if (vcm_.RegisterSendCodec(&current_send_codec, number_of_cores_,
395 max_data_payload_length) != VCM_OK) {
396 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
397 ViEId(engine_id_, channel_id_),
398 "Could not use internal encoder");
399 return -1;
400 }
401 }
402 return 0;
403}
404
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000405int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000406 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
407 ViEId(engine_id_, channel_id_),
408 "%s: CodecType: %d, width: %u, height: %u", __FUNCTION__,
409 video_codec.codecType, video_codec.width, video_codec.height);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000410 // Setting target width and height for VPM.
411 if (vpm_.SetTargetResolution(video_codec.width, video_codec.height,
412 video_codec.maxFramerate) != VPM_OK) {
413 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
414 ViEId(engine_id_, channel_id_),
415 "Could not set VPM target dimensions");
416 return -1;
417 }
418
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000419 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000420 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
421 ViEId(engine_id_, channel_id_),
422 "Could register RTP module video payload");
423 return -1;
424 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000425 // Convert from kbps to bps.
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +0000426 std::vector<uint32_t> stream_bitrates = AllocateStreamBitrates(
427 video_codec.startBitrate * 1000,
428 video_codec.simulcastStream,
429 video_codec.numberOfSimulcastStreams);
430 default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000431
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000432 uint16_t max_data_payload_length =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000433 default_rtp_rtcp_->MaxDataPayloadLength();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000434
stefan@webrtc.org9075d512014-02-14 09:45:58 +0000435 {
436 CriticalSectionScoped cs(data_cs_.get());
437 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
438 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000439 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
440 max_data_payload_length) != VCM_OK) {
441 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
442 ViEId(engine_id_, channel_id_),
443 "Could not register send codec");
444 return -1;
445 }
446
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000447 // Set this module as sending right away, let the slave module in the channel
448 // start and stop sending.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000449 if (default_rtp_rtcp_->Sending() == false) {
450 if (default_rtp_rtcp_->SetSendingStatus(true) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000451 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
452 ViEId(engine_id_, channel_id_),
453 "Could start RTP module sending");
454 return -1;
455 }
456 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000457 bitrate_controller_->SetBitrateObserver(bitrate_observer_.get(),
458 video_codec.startBitrate * 1000,
459 video_codec.minBitrate * 1000,
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000460 kTransmissionMaxBitrateMultiplier *
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000461 video_codec.maxBitrate * 1000);
462
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000463 CriticalSectionScoped crit(data_cs_.get());
464 int pad_up_to_bitrate_kbps = video_codec.startBitrate;
465 if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_)
466 pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_;
467
468 paced_sender_->UpdateBitrate(
469 video_codec.startBitrate, pad_up_to_bitrate_kbps, pad_up_to_bitrate_kbps);
470
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000471 return 0;
472}
473
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000474int32_t ViEEncoder::GetEncoder(VideoCodec* video_codec) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000475 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
476 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
477
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000478 if (vcm_.SendCodec(video_codec) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000479 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
480 ViEId(engine_id_, channel_id_),
481 "Could not get VCM send codec");
482 return -1;
483 }
484 return 0;
485}
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000487int32_t ViEEncoder::GetCodecConfigParameters(
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000488 unsigned char config_parameters[kConfigParameterSize],
489 unsigned char& config_parameters_size) {
490 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
491 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000492
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000493 int32_t num_parameters =
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000494 vcm_.CodecConfigParameters(config_parameters, kConfigParameterSize);
495 if (num_parameters <= 0) {
496 config_parameters_size = 0;
497 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
498 ViEId(engine_id_, channel_id_),
499 "Could not get config parameters");
500 return -1;
501 }
502 config_parameters_size = static_cast<unsigned char>(num_parameters);
503 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504}
505
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000506int32_t ViEEncoder::ScaleInputImage(bool enable) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000507 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
508 ViEId(engine_id_, channel_id_), "%s(enable %d)", __FUNCTION__,
509 enable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000510
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000511 VideoFrameResampling resampling_mode = kFastRescaling;
512 if (enable == true) {
513 // kInterpolation is currently not supported.
514 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
515 ViEId(engine_id_, channel_id_), "%s not supported",
516 __FUNCTION__, enable);
517 return -1;
518 }
519 vpm_.SetInputFrameResampleMode(resampling_mode);
niklase@google.com470e71d2011-07-07 08:21:25 +0000520
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000521 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000522}
523
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000524bool ViEEncoder::TimeToSendPacket(uint32_t ssrc,
525 uint16_t sequence_number,
526 int64_t capture_time_ms,
527 bool retransmission) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000528 return default_rtp_rtcp_->TimeToSendPacket(ssrc, sequence_number,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000529 capture_time_ms, retransmission);
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +0000530}
531
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000532int ViEEncoder::TimeToSendPadding(int bytes) {
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000533 bool send_padding;
534 {
535 CriticalSectionScoped cs(data_cs_.get());
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000536 send_padding =
537 send_padding_ || video_suspended_ || min_transmit_bitrate_kbps_ > 0;
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000538 }
539 if (send_padding) {
stefan@webrtc.org508a84b2013-06-17 12:53:37 +0000540 return default_rtp_rtcp_->TimeToSendPadding(bytes);
541 }
542 return 0;
543}
544
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000545bool ViEEncoder::EncoderPaused() const {
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000546 // Pause video if paused by caller or as long as the network is down or the
547 // pacer queue has grown too large in buffered mode.
548 if (encoder_paused_) {
549 return true;
550 }
551 if (target_delay_ms_ > 0) {
552 // Buffered mode.
553 // TODO(pwestin): Workaround until nack is configured as a time and not
554 // number of packets.
555 return paced_sender_->QueueInMs() >=
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000556 std::max(static_cast<int>(target_delay_ms_ * kEncoderPausePacerMargin),
557 kMinPacingDelayMs);
pwestin@webrtc.org91563e42013-04-25 22:20:08 +0000558 }
559 return !network_is_transmitting_;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000560}
561
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000562RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
563 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
564 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000565
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000566 return default_rtp_rtcp_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +0000567}
568
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000569void ViEEncoder::DeliverFrame(int id,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000570 I420VideoFrame* video_frame,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000571 int num_csrcs,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000572 const uint32_t CSRC[kRtpCsrcSize]) {
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000573 WEBRTC_TRACE(webrtc::kTraceStream,
574 webrtc::kTraceVideo,
575 ViEId(engine_id_, channel_id_),
576 "%s: %llu", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000577 video_frame->timestamp());
wuchengli@chromium.orgac4b87c2014-03-19 03:44:20 +0000578 if (default_rtp_rtcp_->SendingMedia() == false) {
579 // We've paused or we have no channels attached, don't encode.
580 return;
581 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000582 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000583 CriticalSectionScoped cs(data_cs_.get());
stefan@webrtc.org3e005052013-10-18 15:05:29 +0000584 time_of_last_incoming_frame_ms_ = TickTime::MillisecondTimestamp();
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000585 if (EncoderPaused()) {
586 if (!encoder_paused_and_dropped_frame_) {
587 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
588 }
589 encoder_paused_and_dropped_frame_ = true;
590 return;
591 }
592 if (encoder_paused_and_dropped_frame_) {
593 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
594 }
595 encoder_paused_and_dropped_frame_ = false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000596 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000598 // Convert render time, in ms, to RTP timestamp.
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000599 const int kMsToRtpTimestamp = 90;
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000600 const uint32_t time_stamp =
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000601 kMsToRtpTimestamp *
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000602 static_cast<uint32_t>(video_frame->render_time_ms());
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000603
hclam@chromium.org1a7b9b92013-07-08 21:31:18 +0000604 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame->render_time_ms(),
605 "Encode");
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000606 video_frame->set_timestamp(time_stamp);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000607 {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000608 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000609 if (effect_filter_) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000610 unsigned int length = CalcBufferSize(kI420,
611 video_frame->width(),
612 video_frame->height());
613 scoped_array<uint8_t> video_buffer(new uint8_t[length]);
614 ExtractBuffer(*video_frame, length, video_buffer.get());
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000615 effect_filter_->Transform(length,
616 video_buffer.get(),
617 video_frame->timestamp(),
618 video_frame->width(),
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000619 video_frame->height());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000620 }
621 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000622
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000623 // Make sure the CSRC list is correct.
624 if (num_csrcs > 0) {
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000625 uint32_t tempCSRC[kRtpCsrcSize];
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000626 for (int i = 0; i < num_csrcs; i++) {
627 if (CSRC[i] == 1) {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000628 tempCSRC[i] = default_rtp_rtcp_->SSRC();
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000629 } else {
630 tempCSRC[i] = CSRC[i];
631 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000632 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000633 default_rtp_rtcp_->SetCSRCs(tempCSRC, (uint8_t) num_csrcs);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000634 }
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000635 // Pass frame via preprocessor.
636 I420VideoFrame* decimated_frame = NULL;
637 const int ret = vpm_.PreprocessFrame(*video_frame, &decimated_frame);
638 if (ret == 1) {
639 // Drop this frame.
640 return;
641 }
642 if (ret != VPM_OK) {
643 WEBRTC_TRACE(webrtc::kTraceError,
644 webrtc::kTraceVideo,
645 ViEId(engine_id_, channel_id_),
646 "%s: Error preprocessing frame %u", __FUNCTION__,
647 video_frame->timestamp());
648 return;
649 }
650 // Frame was not sampled => use original.
651 if (decimated_frame == NULL) {
652 decimated_frame = video_frame;
653 }
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +0000654
655 {
656 CriticalSectionScoped cs(callback_cs_.get());
657 if (pre_encode_callback_)
658 pre_encode_callback_->FrameCallback(decimated_frame);
659 }
660
niklase@google.com470e71d2011-07-07 08:21:25 +0000661#ifdef VIDEOCODEC_VP8
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000662 if (vcm_.SendCodec() == webrtc::kVideoCodecVP8) {
663 webrtc::CodecSpecificInfo codec_specific_info;
664 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000665 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI =
666 has_received_rpsi_;
667 codec_specific_info.codecSpecific.VP8.hasReceivedSLI =
668 has_received_sli_;
669 codec_specific_info.codecSpecific.VP8.pictureIdRPSI =
670 picture_id_rpsi_;
671 codec_specific_info.codecSpecific.VP8.pictureIdSLI =
672 picture_id_sli_;
673 has_received_sli_ = false;
674 has_received_rpsi_ = false;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000675
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000676 if (vcm_.AddVideoFrame(*decimated_frame,
677 vpm_.ContentMetrics(),
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000678 &codec_specific_info) != VCM_OK) {
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000679 WEBRTC_TRACE(webrtc::kTraceError,
680 webrtc::kTraceVideo,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000681 ViEId(engine_id_, channel_id_),
682 "%s: Error encoding frame %u", __FUNCTION__,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000683 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000684 }
685 return;
686 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000687#endif
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000688 if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) {
pwestin@webrtc.org2f476ed2012-10-30 16:21:52 +0000689 WEBRTC_TRACE(webrtc::kTraceError,
690 webrtc::kTraceVideo,
691 ViEId(engine_id_, channel_id_),
692 "%s: Error encoding frame %u", __FUNCTION__,
693 video_frame->timestamp());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000694 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000695}
niklase@google.com470e71d2011-07-07 08:21:25 +0000696
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000697void ViEEncoder::DelayChanged(int id, int frame_delay) {
698 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
699 ViEId(engine_id_, channel_id_), "%s: %u", __FUNCTION__,
700 frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000702 default_rtp_rtcp_->SetCameraDelay(frame_delay);
niklase@google.com470e71d2011-07-07 08:21:25 +0000703}
niklase@google.com470e71d2011-07-07 08:21:25 +0000704
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000705int ViEEncoder::GetPreferedFrameSettings(int* width,
706 int* height,
707 int* frame_rate) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000708 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
709 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000711 webrtc::VideoCodec video_codec;
712 memset(&video_codec, 0, sizeof(video_codec));
713 if (vcm_.SendCodec(&video_codec) != VCM_OK) {
714 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
715 ViEId(engine_id_, channel_id_),
716 "Could not get VCM send codec");
717 return -1;
718 }
719
mflodman@webrtc.org8baed512012-06-21 12:11:50 +0000720 *width = video_codec.width;
721 *height = video_codec.height;
722 *frame_rate = video_codec.maxFramerate;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000723 return 0;
724}
725
pwestin@webrtc.orgce330352012-04-12 06:59:14 +0000726int ViEEncoder::SendKeyFrame() {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000727 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
728 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
stefan@webrtc.orgc5300432012-10-08 07:06:53 +0000729 return vcm_.IntraFrameRequest(0);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000730}
731
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000732int32_t ViEEncoder::SendCodecStatistics(
733 uint32_t* num_key_frames, uint32_t* num_delta_frames) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000734 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
735 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
736
737 webrtc::VCMFrameCount sent_frames;
738 if (vcm_.SentFrameCount(sent_frames) != VCM_OK) {
739 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
740 ViEId(engine_id_, channel_id_),
741 "%s: Could not get sent frame information", __FUNCTION__);
742 return -1;
743 }
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000744 *num_key_frames = sent_frames.numKeyFrames;
745 *num_delta_frames = sent_frames.numDeltaFrames;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000746 return 0;
747}
748
jiayl@webrtc.org9fd8d872014-02-27 22:32:40 +0000749int32_t ViEEncoder::PacerQueuingDelayMs() const {
750 return paced_sender_->QueueInMs();
751}
752
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000753int32_t ViEEncoder::EstimatedSendBandwidth(
754 uint32_t* available_bandwidth) const {
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000755 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
756 __FUNCTION__);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000757
758 if (!bitrate_controller_->AvailableBandwidth(available_bandwidth)) {
759 return -1;
760 }
761 return 0;
stefan@webrtc.org439be292012-02-16 14:45:37 +0000762}
763
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000764int ViEEncoder::CodecTargetBitrate(uint32_t* bitrate) const {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000765 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
766 __FUNCTION__);
767 if (vcm_.Bitrate(bitrate) != 0)
768 return -1;
769 return 0;
stefan@webrtc.org07b45a52012-02-02 08:37:48 +0000770}
771
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000772int32_t ViEEncoder::UpdateProtectionMethod(bool enable_nack) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000773 bool fec_enabled = false;
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000774 uint8_t dummy_ptype_red = 0;
775 uint8_t dummy_ptypeFEC = 0;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000776
777 // Updated protection method to VCM to get correct packetization sizes.
778 // FEC has larger overhead than NACK -> set FEC if used.
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000779 int32_t error = default_rtp_rtcp_->GenericFECStatus(fec_enabled,
780 dummy_ptype_red,
781 dummy_ptypeFEC);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000782 if (error) {
783 return -1;
784 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000785 if (fec_enabled_ == fec_enabled && nack_enabled_ == enable_nack) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000786 // No change needed, we're already in correct state.
787 return 0;
788 }
789 fec_enabled_ = fec_enabled;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000790 nack_enabled_ = enable_nack;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000791
792 // Set Video Protection for VCM.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000793 if (fec_enabled && nack_enabled_) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000794 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, true);
795 } else {
796 vcm_.SetVideoProtection(webrtc::kProtectionFEC, fec_enabled_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000797 vcm_.SetVideoProtection(webrtc::kProtectionNackSender, nack_enabled_);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000798 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, false);
799 }
800
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000801 if (fec_enabled_ || nack_enabled_) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000802 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
803 ViEId(engine_id_, channel_id_), "%s: FEC status ",
804 __FUNCTION__, fec_enabled);
805 vcm_.RegisterProtectionCallback(this);
806 // The send codec must be registered to set correct MTU.
807 webrtc::VideoCodec codec;
808 if (vcm_.SendCodec(&codec) == 0) {
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000809 uint16_t max_pay_load = default_rtp_rtcp_->MaxDataPayloadLength();
stefan@webrtc.org3d0b0d62013-03-19 10:04:57 +0000810 uint32_t current_bitrate_bps = 0;
811 if (vcm_.Bitrate(&current_bitrate_bps) != 0) {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000812 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
813 ViEId(engine_id_, channel_id_),
814 "Failed to get the current encoder target bitrate.");
815 }
stefan@webrtc.org3d0b0d62013-03-19 10:04:57 +0000816 // Convert to start bitrate in kbps.
817 codec.startBitrate = (current_bitrate_bps + 500) / 1000;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000818 if (vcm_.RegisterSendCodec(&codec, number_of_cores_, max_pay_load) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000819 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000820 ViEId(engine_id_, channel_id_),
821 "%s: Failed to update Sendcodec when enabling FEC",
822 __FUNCTION__, fec_enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +0000823 return -1;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000824 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 }
826 return 0;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000827 } else {
828 // FEC and NACK are disabled.
829 vcm_.RegisterProtectionCallback(NULL);
830 }
831 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000832}
833
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000834void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) {
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000835 {
836 CriticalSectionScoped cs(data_cs_.get());
837 target_delay_ms_ = target_delay_ms;
838 }
mikhal@webrtc.org3d305c62013-02-10 18:42:55 +0000839 if (target_delay_ms > 0) {
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000840 // Disable external frame-droppers.
841 vcm_.EnableFrameDropper(false);
842 vpm_.EnableTemporalDecimation(false);
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000843 // We don't put any limits on the pacer queue when running in buffered mode
844 // since the encoder will be paused if the queue grow too large.
845 paced_sender_->set_max_queue_length_ms(-1);
mikhal@webrtc.org3d305c62013-02-10 18:42:55 +0000846 } else {
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000847 // Real-time mode - enable frame droppers.
mikhal@webrtc.org3d305c62013-02-10 18:42:55 +0000848 vpm_.EnableTemporalDecimation(true);
849 vcm_.EnableFrameDropper(true);
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000850 paced_sender_->set_max_queue_length_ms(
851 PacedSender::kDefaultMaxQueueLengthMs);
mikhal@webrtc.org3d305c62013-02-10 18:42:55 +0000852 }
853}
854
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000855int32_t ViEEncoder::SendData(
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000856 const FrameType frame_type,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000857 const uint8_t payload_type,
858 const uint32_t time_stamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000859 int64_t capture_time_ms,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000860 const uint8_t* payload_data,
861 const uint32_t payload_size,
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000862 const webrtc::RTPFragmentationHeader& fragmentation_header,
863 const RTPVideoHeader* rtp_video_hdr) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000864 // New encoded data, hand over to the rtp module.
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000865 return default_rtp_rtcp_->SendOutgoingData(frame_type,
866 payload_type,
867 time_stamp,
868 capture_time_ms,
869 payload_data,
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000870 payload_size,
871 &fragmentation_header,
872 rtp_video_hdr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000873}
874
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000875int32_t ViEEncoder::ProtectionRequest(
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000876 const FecProtectionParams* delta_fec_params,
877 const FecProtectionParams* key_fec_params,
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000878 uint32_t* sent_video_rate_bps,
879 uint32_t* sent_nack_rate_bps,
880 uint32_t* sent_fec_rate_bps) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000881 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
882 ViEId(engine_id_, channel_id_),
883 "%s, deltaFECRate: %u, key_fecrate: %u, "
marpan@webrtc.org71707aa2012-07-13 16:27:51 +0000884 "delta_use_uep_protection: %d, key_use_uep_protection: %d, "
885 "delta_max_fec_frames: %d, key_max_fec_frames: %d, "
886 "delta_mask_type: %d, key_mask_type: %d, ",
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000887 __FUNCTION__,
888 delta_fec_params->fec_rate,
889 key_fec_params->fec_rate,
890 delta_fec_params->use_uep_protection,
marpan@webrtc.org71707aa2012-07-13 16:27:51 +0000891 key_fec_params->use_uep_protection,
892 delta_fec_params->max_fec_frames,
893 key_fec_params->max_fec_frames,
894 delta_fec_params->fec_mask_type,
895 key_fec_params->fec_mask_type);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000896 if (default_rtp_rtcp_->SetFecParameters(delta_fec_params,
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000897 key_fec_params) != 0) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000898 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
899 ViEId(engine_id_, channel_id_),
stefan@webrtc.orge0d6fa42012-03-20 22:10:56 +0000900 "%s: Could not update FEC parameters", __FUNCTION__);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000901 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000902 default_rtp_rtcp_->BitrateSent(NULL,
stefan@webrtc.orgf4c82862011-12-13 15:38:14 +0000903 sent_video_rate_bps,
904 sent_fec_rate_bps,
905 sent_nack_rate_bps);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000906 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000907}
908
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000909int32_t ViEEncoder::SendStatistics(const uint32_t bit_rate,
910 const uint32_t frame_rate) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000911 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000912 if (codec_observer_) {
913 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
914 ViEId(engine_id_, channel_id_), "%s: bitrate %u, framerate %u",
915 __FUNCTION__, bit_rate, frame_rate);
916 codec_observer_->OutgoingRate(channel_id_, frame_rate, bit_rate);
917 }
918 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000919}
920
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000921int32_t ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +0000922 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000923 if (observer) {
924 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
925 ViEId(engine_id_, channel_id_), "%s: observer added",
926 __FUNCTION__);
927 if (codec_observer_) {
928 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
929 ViEId(engine_id_, channel_id_), "%s: observer already set.",
930 __FUNCTION__);
931 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000933 codec_observer_ = observer;
934 } else {
935 if (codec_observer_ == NULL) {
mflodman@webrtc.orgcdeb4832012-01-18 09:00:04 +0000936 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
937 ViEId(engine_id_, channel_id_),
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000938 "%s: observer does not exist.", __FUNCTION__);
939 return -1;
940 }
941 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
942 ViEId(engine_id_, channel_id_), "%s: observer removed",
943 __FUNCTION__);
944 codec_observer_ = NULL;
945 }
946 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000947}
948
andrew@webrtc.org96636862012-09-20 23:33:17 +0000949void ViEEncoder::OnReceivedSLI(uint32_t /*ssrc*/,
950 uint8_t picture_id) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000951 picture_id_sli_ = picture_id;
952 has_received_sli_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000953}
954
andrew@webrtc.org96636862012-09-20 23:33:17 +0000955void ViEEncoder::OnReceivedRPSI(uint32_t /*ssrc*/,
956 uint64_t picture_id) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000957 picture_id_rpsi_ = picture_id;
958 has_received_rpsi_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000959}
960
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000961void ViEEncoder::OnReceivedIntraFrameRequest(uint32_t ssrc) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000962 // Key frame request from remote side, signal to VCM.
963 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
964 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
justinlin@chromium.org7bfb3a32013-05-13 22:59:00 +0000965 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +0000966
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000967 int idx = 0;
968 {
969 CriticalSectionScoped cs(data_cs_.get());
970 std::map<unsigned int, int>::iterator stream_it = ssrc_streams_.find(ssrc);
971 if (stream_it == ssrc_streams_.end()) {
mflodman@webrtc.orgd73527c2012-12-20 09:26:17 +0000972 LOG_F(LS_WARNING) << "ssrc not found: " << ssrc << ", map size "
973 << ssrc_streams_.size();
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000974 return;
975 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000976 std::map<unsigned int, int64_t>::iterator time_it =
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000977 time_last_intra_request_ms_.find(ssrc);
978 if (time_it == time_last_intra_request_ms_.end()) {
979 time_last_intra_request_ms_[ssrc] = 0;
980 }
981
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000982 int64_t now = TickTime::MillisecondTimestamp();
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000983 if (time_last_intra_request_ms_[ssrc] + kViEMinKeyRequestIntervalMs > now) {
984 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
985 ViEId(engine_id_, channel_id_),
986 "%s: Not encoding new intra due to timing", __FUNCTION__);
987 return;
988 }
989 time_last_intra_request_ms_[ssrc] = now;
990 idx = stream_it->second;
mflodman@webrtc.org84d17832011-12-01 17:02:23 +0000991 }
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000992 // Release the critsect before triggering key frame.
993 vcm_.IntraFrameRequest(idx);
niklase@google.com470e71d2011-07-07 08:21:25 +0000994}
995
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000996void ViEEncoder::OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000997 CriticalSectionScoped cs(data_cs_.get());
998 std::map<unsigned int, int>::iterator it = ssrc_streams_.find(old_ssrc);
999 if (it == ssrc_streams_.end()) {
1000 return;
1001 }
1002
1003 ssrc_streams_[new_ssrc] = it->second;
1004 ssrc_streams_.erase(it);
1005
1006 std::map<unsigned int, int64_t>::iterator time_it =
1007 time_last_intra_request_ms_.find(old_ssrc);
1008 int64_t last_intra_request_ms = 0;
1009 if (time_it != time_last_intra_request_ms_.end()) {
1010 last_intra_request_ms = time_it->second;
1011 time_last_intra_request_ms_.erase(time_it);
1012 }
1013 time_last_intra_request_ms_[new_ssrc] = last_intra_request_ms;
1014}
1015
1016bool ViEEncoder::SetSsrcs(const std::list<unsigned int>& ssrcs) {
1017 VideoCodec codec;
1018 if (vcm_.SendCodec(&codec) != 0)
1019 return false;
1020
1021 if (codec.numberOfSimulcastStreams > 0 &&
1022 ssrcs.size() != codec.numberOfSimulcastStreams) {
1023 return false;
1024 }
1025
1026 CriticalSectionScoped cs(data_cs_.get());
1027 ssrc_streams_.clear();
1028 time_last_intra_request_ms_.clear();
1029 int idx = 0;
1030 for (std::list<unsigned int>::const_iterator it = ssrcs.begin();
1031 it != ssrcs.end(); ++it, ++idx) {
1032 unsigned int ssrc = *it;
1033 ssrc_streams_[ssrc] = idx;
1034 }
1035 return true;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001036}
1037
pbos@webrtc.org3349ae02014-03-13 12:52:27 +00001038void ViEEncoder::SetMinTransmitBitrate(int min_transmit_bitrate_kbps) {
1039 assert(min_transmit_bitrate_kbps >= 0);
1040 CriticalSectionScoped crit(data_cs_.get());
1041 min_transmit_bitrate_kbps_ = min_transmit_bitrate_kbps;
1042}
1043
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001044// Called from ViEBitrateObserver.
1045void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps,
1046 const uint8_t fraction_lost,
1047 const uint32_t round_trip_time_ms) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001048 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1049 ViEId(engine_id_, channel_id_),
1050 "%s(bitrate_bps: %u, fraction_lost: %u, rtt_ms: %u",
1051 __FUNCTION__, bitrate_bps, fraction_lost, round_trip_time_ms);
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00001052
stefan@webrtc.orgabc9d5b2013-03-18 17:00:51 +00001053 vcm_.SetChannelParameters(bitrate_bps, fraction_lost, round_trip_time_ms);
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +00001054 bool video_is_suspended = vcm_.VideoSuspended();
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +00001055 int bitrate_kbps = bitrate_bps / 1000;
stefan@webrtc.org508a84b2013-06-17 12:53:37 +00001056 VideoCodec send_codec;
1057 if (vcm_.SendCodec(&send_codec) != 0) {
1058 return;
1059 }
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +00001060 SimulcastStream* stream_configs = send_codec.simulcastStream;
1061 // Allocate the bandwidth between the streams.
1062 std::vector<uint32_t> stream_bitrates = AllocateStreamBitrates(
1063 bitrate_bps,
1064 stream_configs,
1065 send_codec.numberOfSimulcastStreams);
1066 // Find the max amount of padding we can allow ourselves to send at this
1067 // point, based on which streams are currently active and what our current
1068 // available bandwidth is.
1069 int max_padding_bitrate_kbps = 0;
stefan@webrtc.orgb400aa72013-10-16 13:03:10 +00001070 int pad_up_to_bitrate_kbps = 0;
1071 if (send_codec.numberOfSimulcastStreams == 0) {
1072 max_padding_bitrate_kbps = send_codec.minBitrate;
1073 pad_up_to_bitrate_kbps = send_codec.minBitrate;
1074 } else {
1075 int i = send_codec.numberOfSimulcastStreams - 1;
1076 for (std::vector<uint32_t>::reverse_iterator it = stream_bitrates.rbegin();
1077 it != stream_bitrates.rend(); ++it) {
1078 if (*it > 0) {
1079 max_padding_bitrate_kbps = std::min((*it + 500) / 1000,
1080 stream_configs[i].minBitrate);
1081 break;
1082 }
1083 --i;
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +00001084 }
stefan@webrtc.orgb400aa72013-10-16 13:03:10 +00001085 pad_up_to_bitrate_kbps =
1086 stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate;
1087 for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) {
1088 pad_up_to_bitrate_kbps += stream_configs[i].targetBitrate;
1089 }
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +00001090 }
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +00001091 if (video_is_suspended || send_codec.numberOfSimulcastStreams > 1) {
stefan@webrtc.orgb400aa72013-10-16 13:03:10 +00001092 pad_up_to_bitrate_kbps = std::min(bitrate_kbps, pad_up_to_bitrate_kbps);
1093 } else {
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +00001094 // Disable padding if only sending one stream and video isn't suspended.
stefan@webrtc.orgb400aa72013-10-16 13:03:10 +00001095 pad_up_to_bitrate_kbps = 0;
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +00001096 }
stefan@webrtc.org3e005052013-10-18 15:05:29 +00001097
1098 {
1099 // The amount of padding should decay to zero if no frames are being
1100 // captured.
1101 CriticalSectionScoped cs(data_cs_.get());
1102 int64_t now_ms = TickTime::MillisecondTimestamp();
1103 if (now_ms - time_of_last_incoming_frame_ms_ > kStopPaddingThresholdMs)
1104 max_padding_bitrate_kbps = 0;
1105 }
1106
pbos@webrtc.org484ee962013-11-21 18:44:23 +00001107 {
1108 CriticalSectionScoped cs(data_cs_.get());
pbos@webrtc.org3349ae02014-03-13 12:52:27 +00001109 if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_)
1110 pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_;
1111 if (max_padding_bitrate_kbps < min_transmit_bitrate_kbps_)
1112 max_padding_bitrate_kbps = min_transmit_bitrate_kbps_;
1113 paced_sender_->UpdateBitrate(
1114 bitrate_kbps, max_padding_bitrate_kbps, pad_up_to_bitrate_kbps);
1115 default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
pbos@webrtc.org484ee962013-11-21 18:44:23 +00001116 if (video_suspended_ == video_is_suspended)
1117 return;
1118 video_suspended_ = video_is_suspended;
1119 }
1120 // State changed, inform codec observer.
pbos@webrtc.org3349ae02014-03-13 12:52:27 +00001121 CriticalSectionScoped crit(callback_cs_.get());
pbos@webrtc.org484ee962013-11-21 18:44:23 +00001122 if (codec_observer_) {
1123 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1124 ViEId(engine_id_, channel_id_),
1125 "%s: video_suspended_ changed to %i",
1126 __FUNCTION__, video_is_suspended);
henrik.lundin@webrtc.org9fe36032013-11-21 23:00:40 +00001127 codec_observer_->SuspendChange(channel_id_, video_is_suspended);
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +00001128 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001129}
1130
pwestin@webrtc.org571a1c02012-11-13 21:12:39 +00001131PacedSender* ViEEncoder::GetPacedSender() {
1132 return paced_sender_.get();
1133}
1134
pbos@webrtc.orgb238d122013-04-09 13:41:51 +00001135int32_t ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
mflodman@webrtc.orgd32c4472011-12-22 14:17:53 +00001136 CriticalSectionScoped cs(callback_cs_.get());
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001137 if (effect_filter == NULL) {
1138 if (effect_filter_ == NULL) {
1139 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1140 ViEId(engine_id_, channel_id_), "%s: no effect filter added",
1141 __FUNCTION__);
1142 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001143 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001144 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1145 ViEId(engine_id_, channel_id_), "%s: deregister effect filter",
1146 __FUNCTION__);
1147 } else {
1148 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1149 ViEId(engine_id_, channel_id_), "%s: register effect",
1150 __FUNCTION__);
1151 if (effect_filter_) {
1152 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1153 ViEId(engine_id_, channel_id_),
1154 "%s: effect filter already added ", __FUNCTION__);
1155 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001156 }
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001157 }
1158 effect_filter_ = effect_filter;
1159 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001160}
1161
mikhal@webrtc.orge41bbdf2012-08-28 16:15:16 +00001162int ViEEncoder::StartDebugRecording(const char* fileNameUTF8) {
1163 return vcm_.StartDebugRecording(fileNameUTF8);
1164}
1165
1166int ViEEncoder::StopDebugRecording() {
1167 return vcm_.StopDebugRecording();
1168}
1169
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +00001170void ViEEncoder::SuspendBelowMinBitrate() {
1171 vcm_.SuspendBelowMinBitrate();
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +00001172 bitrate_controller_->EnforceMinBitrate(false);
henrik.lundin@webrtc.org845862f2014-03-06 07:19:28 +00001173 bitrate_controller_->SetBweMinBitrate(10000);
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +00001174}
1175
pbos@webrtc.orgfe1ef932013-10-21 10:34:43 +00001176void ViEEncoder::RegisterPreEncodeCallback(
1177 I420FrameCallback* pre_encode_callback) {
1178 CriticalSectionScoped cs(callback_cs_.get());
1179 pre_encode_callback_ = pre_encode_callback;
1180}
1181
1182void ViEEncoder::DeRegisterPreEncodeCallback() {
1183 CriticalSectionScoped cs(callback_cs_.get());
1184 pre_encode_callback_ = NULL;
1185}
1186
sprang@webrtc.org40709352013-11-26 11:41:59 +00001187void ViEEncoder::RegisterPostEncodeImageCallback(
1188 EncodedImageCallback* post_encode_callback) {
1189 vcm_.RegisterPostEncodeImageCallback(post_encode_callback);
1190}
1191
1192void ViEEncoder::DeRegisterPostEncodeImageCallback() {
1193 vcm_.RegisterPostEncodeImageCallback(NULL);
1194}
1195
marpan@webrtc.orgefd01fd2012-04-18 15:56:34 +00001196QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessingModule* vpm)
1197 : vpm_(vpm) {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001198}
niklase@google.com470e71d2011-07-07 08:21:25 +00001199
stefan@webrtc.org439be292012-02-16 14:45:37 +00001200QMVideoSettingsCallback::~QMVideoSettingsCallback() {
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001201}
1202
pbos@webrtc.orgb238d122013-04-09 13:41:51 +00001203int32_t QMVideoSettingsCallback::SetVideoQMSettings(
1204 const uint32_t frame_rate,
1205 const uint32_t width,
1206 const uint32_t height) {
marpan@webrtc.orgcf706c22012-03-27 21:04:13 +00001207 return vpm_->SetTargetResolution(width, height, frame_rate);
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001208}
1209
mflodman@webrtc.org84d17832011-12-01 17:02:23 +00001210} // namespace webrtc