blob: e91645bab3ea4ff972fa452cc3d5e983e79428e0 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 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.org281cff82013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_encoder.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
stefan@webrtc.org695ff2a2013-06-04 09:36:56 +000013#include <algorithm>
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000014#include <cassert>
15
pbos@webrtc.org281cff82013-05-17 13:44:48 +000016#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
17#include "webrtc/modules/pacing/include/paced_sender.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
19#include "webrtc/modules/utility/interface/process_thread.h"
20#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
21#include "webrtc/modules/video_coding/main/interface/video_coding.h"
22#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/tick_util.h"
26#include "webrtc/system_wrappers/interface/trace.h"
27#include "webrtc/system_wrappers/interface/trace_event.h"
28#include "webrtc/video_engine/include/vie_codec.h"
29#include "webrtc/video_engine/include/vie_image_process.h"
30#include "webrtc/video_engine/vie_defines.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000031
32namespace webrtc {
33
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000034// Pace in kbits/s until we receive first estimate.
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +000035static const int kInitialPace = 2000;
pwestin@webrtc.org3816c522013-04-25 22:20:08 +000036
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +000037// Pacing-rate relative to our target send rate.
38// Multiplicative factor that is applied to the target bitrate to calculate the
39// number of bytes that can be transmitted per interval.
40// Increasing this factor will result in lower delays in cases of bitrate
41// overshoots from the encoder.
42static const float kPaceMultiplier = 2.5f;
43
44// Margin on when we pause the encoder when the pacing buffer overflows relative
45// to the configured buffer delay.
46static const float kEncoderPausePacerMargin = 2.0f;
47
pwestin@webrtc.org3816c522013-04-25 22:20:08 +000048// Don't stop the encoder unless the delay is above this configured value.
49static const int kMinPacingDelayMs = 200;
50
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +000051// Allow packets to be transmitted in up to 2 times max video bitrate if the
52// bandwidth estimate allows it.
53// TODO(holmer): Expose transmission start, min and max bitrates in the
54// VideoEngine API and remove the kTransmissionMaxBitrateMultiplier.
55static const int kTransmissionMaxBitrateMultiplier = 2;
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000056
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000057class QMVideoSettingsCallback : public VCMQMSettingsCallback {
58 public:
59 explicit QMVideoSettingsCallback(VideoProcessingModule* vpm);
60 ~QMVideoSettingsCallback();
61
62 // Update VPM with QM (quality modes: frame size & frame rate) settings.
pbos@webrtc.org67879bc2013-04-09 13:41:51 +000063 int32_t SetVideoQMSettings(const uint32_t frame_rate,
64 const uint32_t width,
65 const uint32_t height);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000066
67 private:
68 VideoProcessingModule* vpm_;
69};
70
71class ViEBitrateObserver : public BitrateObserver {
72 public:
73 explicit ViEBitrateObserver(ViEEncoder* owner)
74 : owner_(owner) {
75 }
76 // Implements BitrateObserver.
77 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
78 const uint8_t fraction_lost,
79 const uint32_t rtt) {
80 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
81 }
82 private:
83 ViEEncoder* owner_;
84};
85
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000086class ViEPacedSenderCallback : public PacedSender::Callback {
87 public:
88 explicit ViEPacedSenderCallback(ViEEncoder* owner)
89 : owner_(owner) {
90 }
hclam@chromium.org0f6f7cb2013-06-20 20:18:31 +000091 virtual bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000092 int64_t capture_time_ms) {
hclam@chromium.org0f6f7cb2013-06-20 20:18:31 +000093 return owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000094 }
stefan@webrtc.org695ff2a2013-06-04 09:36:56 +000095 virtual int TimeToSendPadding(int bytes) {
stefan@webrtc.org69f76052013-06-17 12:53:37 +000096 return owner_->TimeToSendPadding(bytes);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +000097 }
98 private:
99 ViEEncoder* owner_;
100};
101
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000102ViEEncoder::ViEEncoder(int32_t engine_id,
103 int32_t channel_id,
104 uint32_t number_of_cores,
andresp@webrtc.orgac6d9192013-05-13 10:50:50 +0000105 const Config& config,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000106 ProcessThread& module_process_thread,
107 BitrateController* bitrate_controller)
108 : engine_id_(engine_id),
109 channel_id_(channel_id),
110 number_of_cores_(number_of_cores),
111 vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
112 channel_id))),
113 vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
114 channel_id))),
115 default_rtp_rtcp_(NULL),
116 callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
117 data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
118 bitrate_controller_(bitrate_controller),
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000119 send_padding_(false),
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000120 target_delay_ms_(0),
121 network_is_transmitting_(true),
122 encoder_paused_(false),
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +0000123 encoder_paused_and_dropped_frame_(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000124 channels_dropping_delta_frames_(0),
125 drop_next_frame_(false),
126 fec_enabled_(false),
127 nack_enabled_(false),
128 codec_observer_(NULL),
129 effect_filter_(NULL),
130 module_process_thread_(module_process_thread),
131 has_received_sli_(false),
132 picture_id_sli_(0),
133 has_received_rpsi_(false),
134 picture_id_rpsi_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000135 qm_callback_(NULL) {
136 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
137 ViEId(engine_id, channel_id),
138 "%s(engine_id: %d) 0x%p - Constructor", __FUNCTION__, engine_id,
139 this);
140
141 RtpRtcp::Configuration configuration;
142 configuration.id = ViEModuleId(engine_id_, channel_id_);
143 configuration.audio = false; // Video.
144
145 default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
146 bitrate_observer_.reset(new ViEBitrateObserver(this));
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000147 pacing_callback_.reset(new ViEPacedSenderCallback(this));
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +0000148 paced_sender_.reset(
149 new PacedSender(pacing_callback_.get(), kInitialPace, kPaceMultiplier));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000150}
151
152bool ViEEncoder::Init() {
153 if (vcm_.InitializeSender() != 0) {
154 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
155 ViEId(engine_id_, channel_id_),
156 "%s InitializeSender failure", __FUNCTION__);
157 return false;
158 }
159 vpm_.EnableTemporalDecimation(true);
160
161 // Enable/disable content analysis: off by default for now.
162 vpm_.EnableContentAnalysis(false);
163
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000164 if (module_process_thread_.RegisterModule(&vcm_) != 0 ||
165 module_process_thread_.RegisterModule(default_rtp_rtcp_.get()) != 0 ||
166 module_process_thread_.RegisterModule(paced_sender_.get()) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000167 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
168 ViEId(engine_id_, channel_id_),
169 "%s RegisterModule failure", __FUNCTION__);
170 return false;
171 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000172 if (qm_callback_) {
173 delete qm_callback_;
174 }
175 qm_callback_ = new QMVideoSettingsCallback(&vpm_);
176
177#ifdef VIDEOCODEC_VP8
178 VideoCodec video_codec;
179 if (vcm_.Codec(webrtc::kVideoCodecVP8, &video_codec) != VCM_OK) {
180 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
181 ViEId(engine_id_, channel_id_),
182 "%s Codec failure", __FUNCTION__);
183 return false;
184 }
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000185 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000186 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
187 default_rtp_rtcp_->MaxDataPayloadLength()) != 0) {
188 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
189 ViEId(engine_id_, channel_id_),
190 "%s RegisterSendCodec failure", __FUNCTION__);
191 return false;
192 }
193 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
194 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
195 ViEId(engine_id_, channel_id_),
196 "%s RegisterSendPayload failure", __FUNCTION__);
197 return false;
198 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000199#else
200 VideoCodec video_codec;
201 if (vcm_.Codec(webrtc::kVideoCodecI420, &video_codec) == VCM_OK) {
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000202 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000203 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
204 default_rtp_rtcp_->MaxDataPayloadLength());
205 default_rtp_rtcp_->RegisterSendPayload(video_codec);
206 } else {
207 return false;
208 }
209#endif
210
211 if (vcm_.RegisterTransportCallback(this) != 0) {
212 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
213 ViEId(engine_id_, channel_id_),
214 "ViEEncoder: VCM::RegisterTransportCallback failure");
215 return false;
216 }
217 if (vcm_.RegisterSendStatisticsCallback(this) != 0) {
218 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
219 ViEId(engine_id_, channel_id_),
220 "ViEEncoder: VCM::RegisterSendStatisticsCallback failure");
221 return false;
222 }
223 if (vcm_.RegisterVideoQMCallback(qm_callback_) != 0) {
224 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
225 ViEId(engine_id_, channel_id_),
226 "VCM::RegisterQMCallback failure");
227 return false;
228 }
229 return true;
230}
231
232ViEEncoder::~ViEEncoder() {
233 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
234 ViEId(engine_id_, channel_id_),
235 "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
stefan@webrtc.orgc0539d92012-11-29 09:18:53 +0000236 if (bitrate_controller_) {
237 bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
238 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000239 module_process_thread_.DeRegisterModule(&vcm_);
240 module_process_thread_.DeRegisterModule(&vpm_);
241 module_process_thread_.DeRegisterModule(default_rtp_rtcp_.get());
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000242 module_process_thread_.DeRegisterModule(paced_sender_.get());
mflodman@webrtc.orgc6242c92013-03-01 14:51:23 +0000243 VideoCodingModule::Destroy(&vcm_);
244 VideoProcessingModule::Destroy(&vpm_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000245 delete qm_callback_;
246}
247
248int ViEEncoder::Owner() const {
249 return channel_id_;
250}
251
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000252void ViEEncoder::SetNetworkTransmissionState(bool is_transmitting) {
253 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
254 ViEId(engine_id_, channel_id_),
255 "%s(%s)", __FUNCTION__,
256 is_transmitting ? "transmitting" : "not transmitting");
257 {
258 CriticalSectionScoped cs(data_cs_.get());
259 network_is_transmitting_ = is_transmitting;
260 }
261 if (is_transmitting) {
262 paced_sender_->Resume();
263 } else {
264 paced_sender_->Pause();
265 }
266}
267
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000268void ViEEncoder::Pause() {
269 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
270 ViEId(engine_id_, channel_id_),
271 "%s", __FUNCTION__);
272 CriticalSectionScoped cs(data_cs_.get());
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000273 encoder_paused_ = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000274}
275
276void ViEEncoder::Restart() {
277 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
278 ViEId(engine_id_, channel_id_),
279 "%s", __FUNCTION__);
280 CriticalSectionScoped cs(data_cs_.get());
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000281 encoder_paused_ = false;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000282}
283
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000284int32_t ViEEncoder::DropDeltaAfterKey(bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000285 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
286 ViEId(engine_id_, channel_id_),
287 "%s(%d)", __FUNCTION__, enable);
288 CriticalSectionScoped cs(data_cs_.get());
289
290 if (enable) {
291 channels_dropping_delta_frames_++;
292 } else {
293 channels_dropping_delta_frames_--;
294 if (channels_dropping_delta_frames_ < 0) {
295 channels_dropping_delta_frames_ = 0;
296 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
297 ViEId(engine_id_, channel_id_),
298 "%s: Called too many times", __FUNCTION__);
299 return -1;
300 }
301 }
302 return 0;
303}
304
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000305uint8_t ViEEncoder::NumberOfCodecs() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000306 return vcm_.NumberOfCodecs();
307}
308
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000309int32_t ViEEncoder::GetCodec(uint8_t list_index, VideoCodec* video_codec) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000310 if (vcm_.Codec(list_index, video_codec) != 0) {
311 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
312 ViEId(engine_id_, channel_id_), "%s: Could not get codec",
313 __FUNCTION__);
314 return -1;
315 }
316 return 0;
317}
318
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000319int32_t ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
320 uint8_t pl_type,
321 bool internal_source) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000322 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
323 ViEId(engine_id_, channel_id_), "%s: pltype %u", __FUNCTION__,
324 pl_type);
325
326 if (encoder == NULL)
327 return -1;
328
stefan@webrtc.org71f3f682013-01-09 08:35:40 +0000329 if (vcm_.RegisterExternalEncoder(encoder, pl_type, internal_source) !=
330 VCM_OK) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000331 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
332 ViEId(engine_id_, channel_id_),
333 "Could not register external encoder");
334 return -1;
335 }
336 return 0;
337}
338
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000339int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000340 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
341 ViEId(engine_id_, channel_id_),
342 "%s: pltype %u", __FUNCTION__, pl_type);
343
344 webrtc::VideoCodec current_send_codec;
345 if (vcm_.SendCodec(&current_send_codec) == VCM_OK) {
stefan@webrtc.org63136922013-03-19 10:04:57 +0000346 uint32_t current_bitrate_bps = 0;
347 if (vcm_.Bitrate(&current_bitrate_bps) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000348 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
349 ViEId(engine_id_, channel_id_),
350 "Failed to get the current encoder target bitrate.");
351 }
stefan@webrtc.org63136922013-03-19 10:04:57 +0000352 current_send_codec.startBitrate = (current_bitrate_bps + 500) / 1000;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000353 }
354
355 if (vcm_.RegisterExternalEncoder(NULL, pl_type) != VCM_OK) {
356 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
357 ViEId(engine_id_, channel_id_),
358 "Could not deregister external encoder");
359 return -1;
360 }
361
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000362 // If the external encoder is the current send codec, use vcm internal
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000363 // encoder.
364 if (current_send_codec.plType == pl_type) {
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000365 uint16_t max_data_payload_length =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000366 default_rtp_rtcp_->MaxDataPayloadLength();
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000367 send_padding_ = current_send_codec.numberOfSimulcastStreams > 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000368 if (vcm_.RegisterSendCodec(&current_send_codec, number_of_cores_,
369 max_data_payload_length) != VCM_OK) {
370 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
371 ViEId(engine_id_, channel_id_),
372 "Could not use internal encoder");
373 return -1;
374 }
375 }
376 return 0;
377}
378
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000379int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000380 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
381 ViEId(engine_id_, channel_id_),
382 "%s: CodecType: %d, width: %u, height: %u", __FUNCTION__,
383 video_codec.codecType, video_codec.width, video_codec.height);
384
385 // Setting target width and height for VPM.
386 if (vpm_.SetTargetResolution(video_codec.width, video_codec.height,
387 video_codec.maxFramerate) != VPM_OK) {
388 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
389 ViEId(engine_id_, channel_id_),
390 "Could not set VPM target dimensions");
391 return -1;
392 }
393
394 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
395 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
396 ViEId(engine_id_, channel_id_),
397 "Could register RTP module video payload");
398 return -1;
399 }
400 // Convert from kbps to bps.
401 default_rtp_rtcp_->SetTargetSendBitrate(video_codec.startBitrate * 1000);
402
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000403 uint16_t max_data_payload_length =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000404 default_rtp_rtcp_->MaxDataPayloadLength();
405
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000406 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000407 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
408 max_data_payload_length) != VCM_OK) {
409 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
410 ViEId(engine_id_, channel_id_),
411 "Could not register send codec");
412 return -1;
413 }
414
415 // Set this module as sending right away, let the slave module in the channel
416 // start and stop sending.
417 if (default_rtp_rtcp_->Sending() == false) {
418 if (default_rtp_rtcp_->SetSendingStatus(true) != 0) {
419 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
420 ViEId(engine_id_, channel_id_),
421 "Could start RTP module sending");
422 return -1;
423 }
424 }
425 bitrate_controller_->SetBitrateObserver(bitrate_observer_.get(),
426 video_codec.startBitrate * 1000,
427 video_codec.minBitrate * 1000,
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000428 kTransmissionMaxBitrateMultiplier *
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000429 video_codec.maxBitrate * 1000);
430
431 return 0;
432}
433
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000434int32_t ViEEncoder::GetEncoder(VideoCodec* video_codec) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000435 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
436 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
437
438 if (vcm_.SendCodec(video_codec) != 0) {
439 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
440 ViEId(engine_id_, channel_id_),
441 "Could not get VCM send codec");
442 return -1;
443 }
444 return 0;
445}
446
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000447int32_t ViEEncoder::GetCodecConfigParameters(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000448 unsigned char config_parameters[kConfigParameterSize],
449 unsigned char& config_parameters_size) {
450 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
451 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
452
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000453 int32_t num_parameters =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000454 vcm_.CodecConfigParameters(config_parameters, kConfigParameterSize);
455 if (num_parameters <= 0) {
456 config_parameters_size = 0;
457 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
458 ViEId(engine_id_, channel_id_),
459 "Could not get config parameters");
460 return -1;
461 }
462 config_parameters_size = static_cast<unsigned char>(num_parameters);
463 return 0;
464}
465
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000466int32_t ViEEncoder::ScaleInputImage(bool enable) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000467 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
468 ViEId(engine_id_, channel_id_), "%s(enable %d)", __FUNCTION__,
469 enable);
470
471 VideoFrameResampling resampling_mode = kFastRescaling;
472 if (enable == true) {
473 // kInterpolation is currently not supported.
474 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
475 ViEId(engine_id_, channel_id_), "%s not supported",
476 __FUNCTION__, enable);
477 return -1;
478 }
479 vpm_.SetInputFrameResampleMode(resampling_mode);
480
481 return 0;
482}
483
hclam@chromium.org0f6f7cb2013-06-20 20:18:31 +0000484bool ViEEncoder::TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000485 int64_t capture_time_ms) {
hclam@chromium.org0f6f7cb2013-06-20 20:18:31 +0000486 return default_rtp_rtcp_->TimeToSendPacket(ssrc, sequence_number,
487 capture_time_ms);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +0000488}
489
stefan@webrtc.org69f76052013-06-17 12:53:37 +0000490int ViEEncoder::TimeToSendPadding(int bytes) {
491 if (send_padding_) {
492 return default_rtp_rtcp_->TimeToSendPadding(bytes);
493 }
494 return 0;
495}
496
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000497bool ViEEncoder::EncoderPaused() const {
pwestin@webrtc.org3816c522013-04-25 22:20:08 +0000498 // Pause video if paused by caller or as long as the network is down or the
499 // pacer queue has grown too large in buffered mode.
500 if (encoder_paused_) {
501 return true;
502 }
503 if (target_delay_ms_ > 0) {
504 // Buffered mode.
505 // TODO(pwestin): Workaround until nack is configured as a time and not
506 // number of packets.
507 return paced_sender_->QueueInMs() >=
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +0000508 std::max(static_cast<int>(target_delay_ms_ * kEncoderPausePacerMargin),
509 kMinPacingDelayMs);
pwestin@webrtc.org3816c522013-04-25 22:20:08 +0000510 }
511 return !network_is_transmitting_;
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000512}
513
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000514RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
515 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
516 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
517
518 return default_rtp_rtcp_.get();
519}
520
521void ViEEncoder::DeliverFrame(int id,
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000522 I420VideoFrame* video_frame,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000523 int num_csrcs,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000524 const uint32_t CSRC[kRtpCsrcSize]) {
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000525 WEBRTC_TRACE(webrtc::kTraceStream,
526 webrtc::kTraceVideo,
527 ViEId(engine_id_, channel_id_),
528 "%s: %llu", __FUNCTION__,
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000529 video_frame->timestamp());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000530 {
531 CriticalSectionScoped cs(data_cs_.get());
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +0000532 if (default_rtp_rtcp_->SendingMedia() == false) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000533 // We've paused or we have no channels attached, don't encode.
534 return;
535 }
pwestin@webrtc.org36bdba42013-05-02 19:02:17 +0000536 if (EncoderPaused()) {
537 if (!encoder_paused_and_dropped_frame_) {
538 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
539 }
540 encoder_paused_and_dropped_frame_ = true;
541 return;
542 }
543 if (encoder_paused_and_dropped_frame_) {
544 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
545 }
546 encoder_paused_and_dropped_frame_ = false;
547
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000548 if (drop_next_frame_) {
549 // Drop this frame.
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000550 WEBRTC_TRACE(webrtc::kTraceStream,
551 webrtc::kTraceVideo,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000552 ViEId(engine_id_, channel_id_),
553 "%s: Dropping frame %llu after a key fame", __FUNCTION__,
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000554 video_frame->timestamp());
hclam@chromium.org74472fe2013-04-09 19:54:10 +0000555 TRACE_EVENT_INSTANT1("webrtc", "VE::EncoderDropFrame",
556 "timestamp", video_frame->timestamp());
557
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000558 drop_next_frame_ = false;
559 return;
560 }
561 }
562
563 // Convert render time, in ms, to RTP timestamp.
564 const int kMsToRtpTimestamp = 90;
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000565 const uint32_t time_stamp =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000566 kMsToRtpTimestamp *
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000567 static_cast<uint32_t>(video_frame->render_time_ms());
hclam@chromium.org74472fe2013-04-09 19:54:10 +0000568
569 TRACE_EVENT2("webrtc", "VE::DeliverFrame",
570 "timestamp", time_stamp,
571 "render_time", video_frame->render_time_ms());
572
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000573 video_frame->set_timestamp(time_stamp);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000574 {
575 CriticalSectionScoped cs(callback_cs_.get());
576 if (effect_filter_) {
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000577 unsigned int length = CalcBufferSize(kI420,
578 video_frame->width(),
579 video_frame->height());
580 scoped_array<uint8_t> video_buffer(new uint8_t[length]);
581 ExtractBuffer(*video_frame, length, video_buffer.get());
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000582 effect_filter_->Transform(length,
583 video_buffer.get(),
584 video_frame->timestamp(),
585 video_frame->width(),
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000586 video_frame->height());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000587 }
588 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000589
590 // Make sure the CSRC list is correct.
591 if (num_csrcs > 0) {
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000592 uint32_t tempCSRC[kRtpCsrcSize];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000593 for (int i = 0; i < num_csrcs; i++) {
594 if (CSRC[i] == 1) {
595 tempCSRC[i] = default_rtp_rtcp_->SSRC();
596 } else {
597 tempCSRC[i] = CSRC[i];
598 }
599 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000600 default_rtp_rtcp_->SetCSRCs(tempCSRC, (uint8_t) num_csrcs);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000601 }
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000602 // Pass frame via preprocessor.
603 I420VideoFrame* decimated_frame = NULL;
604 const int ret = vpm_.PreprocessFrame(*video_frame, &decimated_frame);
605 if (ret == 1) {
606 // Drop this frame.
607 return;
608 }
609 if (ret != VPM_OK) {
610 WEBRTC_TRACE(webrtc::kTraceError,
611 webrtc::kTraceVideo,
612 ViEId(engine_id_, channel_id_),
613 "%s: Error preprocessing frame %u", __FUNCTION__,
614 video_frame->timestamp());
615 return;
616 }
617 // Frame was not sampled => use original.
618 if (decimated_frame == NULL) {
619 decimated_frame = video_frame;
620 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000621#ifdef VIDEOCODEC_VP8
622 if (vcm_.SendCodec() == webrtc::kVideoCodecVP8) {
623 webrtc::CodecSpecificInfo codec_specific_info;
624 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000625 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI =
626 has_received_rpsi_;
627 codec_specific_info.codecSpecific.VP8.hasReceivedSLI =
628 has_received_sli_;
629 codec_specific_info.codecSpecific.VP8.pictureIdRPSI =
630 picture_id_rpsi_;
631 codec_specific_info.codecSpecific.VP8.pictureIdSLI =
632 picture_id_sli_;
633 has_received_sli_ = false;
634 has_received_rpsi_ = false;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000635
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000636 if (vcm_.AddVideoFrame(*decimated_frame,
637 vpm_.ContentMetrics(),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000638 &codec_specific_info) != VCM_OK) {
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000639 WEBRTC_TRACE(webrtc::kTraceError,
640 webrtc::kTraceVideo,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000641 ViEId(engine_id_, channel_id_),
642 "%s: Error encoding frame %u", __FUNCTION__,
mikhal@webrtc.org3bbed742012-10-24 18:33:04 +0000643 video_frame->timestamp());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000644 }
645 return;
646 }
647#endif
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000648 if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) {
pwestin@webrtc.org28f76e52012-10-30 16:21:52 +0000649 WEBRTC_TRACE(webrtc::kTraceError,
650 webrtc::kTraceVideo,
651 ViEId(engine_id_, channel_id_),
652 "%s: Error encoding frame %u", __FUNCTION__,
653 video_frame->timestamp());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000654 }
655}
656
657void ViEEncoder::DelayChanged(int id, int frame_delay) {
658 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
659 ViEId(engine_id_, channel_id_), "%s: %u", __FUNCTION__,
660 frame_delay);
661
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000662 default_rtp_rtcp_->SetCameraDelay(frame_delay);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000663}
664
665int ViEEncoder::GetPreferedFrameSettings(int* width,
666 int* height,
667 int* frame_rate) {
668 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
669 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
670
671 webrtc::VideoCodec video_codec;
672 memset(&video_codec, 0, sizeof(video_codec));
673 if (vcm_.SendCodec(&video_codec) != VCM_OK) {
674 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
675 ViEId(engine_id_, channel_id_),
676 "Could not get VCM send codec");
677 return -1;
678 }
679
680 *width = video_codec.width;
681 *height = video_codec.height;
682 *frame_rate = video_codec.maxFramerate;
683 return 0;
684}
685
686int ViEEncoder::SendKeyFrame() {
687 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
688 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
689 return vcm_.IntraFrameRequest(0);
690}
691
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000692int32_t ViEEncoder::SendCodecStatistics(
693 uint32_t* num_key_frames, uint32_t* num_delta_frames) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000694 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
695 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
696
697 webrtc::VCMFrameCount sent_frames;
698 if (vcm_.SentFrameCount(sent_frames) != VCM_OK) {
699 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
700 ViEId(engine_id_, channel_id_),
701 "%s: Could not get sent frame information", __FUNCTION__);
702 return -1;
703 }
704 *num_key_frames = sent_frames.numKeyFrames;
705 *num_delta_frames = sent_frames.numDeltaFrames;
706 return 0;
707}
708
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000709int32_t ViEEncoder::EstimatedSendBandwidth(
710 uint32_t* available_bandwidth) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000711 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
712 __FUNCTION__);
713
714 if (!bitrate_controller_->AvailableBandwidth(available_bandwidth)) {
715 return -1;
716 }
717 return 0;
718}
719
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000720int ViEEncoder::CodecTargetBitrate(uint32_t* bitrate) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000721 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
722 __FUNCTION__);
723 if (vcm_.Bitrate(bitrate) != 0)
724 return -1;
725 return 0;
726}
727
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000728int32_t ViEEncoder::UpdateProtectionMethod() {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000729 bool fec_enabled = false;
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000730 uint8_t dummy_ptype_red = 0;
731 uint8_t dummy_ptypeFEC = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000732
733 // Updated protection method to VCM to get correct packetization sizes.
734 // FEC has larger overhead than NACK -> set FEC if used.
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000735 int32_t error = default_rtp_rtcp_->GenericFECStatus(fec_enabled,
736 dummy_ptype_red,
737 dummy_ptypeFEC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000738 if (error) {
739 return -1;
740 }
741
742 bool nack_enabled = (default_rtp_rtcp_->NACK() == kNackOff) ? false : true;
743 if (fec_enabled_ == fec_enabled && nack_enabled_ == nack_enabled) {
744 // No change needed, we're already in correct state.
745 return 0;
746 }
747 fec_enabled_ = fec_enabled;
748 nack_enabled_ = nack_enabled;
749
750 // Set Video Protection for VCM.
751 if (fec_enabled && nack_enabled) {
752 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, true);
753 } else {
754 vcm_.SetVideoProtection(webrtc::kProtectionFEC, fec_enabled_);
755 vcm_.SetVideoProtection(webrtc::kProtectionNack, nack_enabled_);
756 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, false);
757 }
758
759 if (fec_enabled || nack_enabled) {
760 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
761 ViEId(engine_id_, channel_id_), "%s: FEC status ",
762 __FUNCTION__, fec_enabled);
763 vcm_.RegisterProtectionCallback(this);
764 // The send codec must be registered to set correct MTU.
765 webrtc::VideoCodec codec;
766 if (vcm_.SendCodec(&codec) == 0) {
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000767 uint16_t max_pay_load = default_rtp_rtcp_->MaxDataPayloadLength();
stefan@webrtc.org63136922013-03-19 10:04:57 +0000768 uint32_t current_bitrate_bps = 0;
769 if (vcm_.Bitrate(&current_bitrate_bps) != 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000770 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
771 ViEId(engine_id_, channel_id_),
772 "Failed to get the current encoder target bitrate.");
773 }
stefan@webrtc.org63136922013-03-19 10:04:57 +0000774 // Convert to start bitrate in kbps.
775 codec.startBitrate = (current_bitrate_bps + 500) / 1000;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000776 if (vcm_.RegisterSendCodec(&codec, number_of_cores_, max_pay_load) != 0) {
777 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
778 ViEId(engine_id_, channel_id_),
779 "%s: Failed to update Sendcodec when enabling FEC",
780 __FUNCTION__, fec_enabled);
781 return -1;
782 }
783 }
784 return 0;
785 } else {
786 // FEC and NACK are disabled.
787 vcm_.RegisterProtectionCallback(NULL);
788 }
789 return 0;
790}
791
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000792void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) {
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000793 {
794 CriticalSectionScoped cs(data_cs_.get());
795 target_delay_ms_ = target_delay_ms;
796 }
mikhal@webrtc.org0c66de62013-02-10 18:42:55 +0000797 if (target_delay_ms > 0) {
stefan@webrtc.orgdca71b22013-03-27 16:36:01 +0000798 // Disable external frame-droppers.
799 vcm_.EnableFrameDropper(false);
800 vpm_.EnableTemporalDecimation(false);
mikhal@webrtc.org0c66de62013-02-10 18:42:55 +0000801 } else {
mikhal@webrtc.org9d6fcb32013-02-15 23:22:18 +0000802 // Real-time mode - enable frame droppers.
mikhal@webrtc.org0c66de62013-02-10 18:42:55 +0000803 vpm_.EnableTemporalDecimation(true);
804 vcm_.EnableFrameDropper(true);
805 }
806}
807
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000808int32_t ViEEncoder::SendData(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000809 const FrameType frame_type,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000810 const uint8_t payload_type,
811 const uint32_t time_stamp,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000812 int64_t capture_time_ms,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000813 const uint8_t* payload_data,
814 const uint32_t payload_size,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000815 const webrtc::RTPFragmentationHeader& fragmentation_header,
816 const RTPVideoHeader* rtp_video_hdr) {
817 {
818 CriticalSectionScoped cs(data_cs_.get());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000819 if (channels_dropping_delta_frames_ &&
820 frame_type == webrtc::kVideoFrameKey) {
821 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
822 ViEId(engine_id_, channel_id_),
823 "%s: Sending key frame, drop next frame", __FUNCTION__);
824 drop_next_frame_ = true;
825 }
826 }
827
828 // New encoded data, hand over to the rtp module.
829 return default_rtp_rtcp_->SendOutgoingData(frame_type,
830 payload_type,
831 time_stamp,
832 capture_time_ms,
833 payload_data,
834 payload_size,
835 &fragmentation_header,
836 rtp_video_hdr);
837}
838
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000839int32_t ViEEncoder::ProtectionRequest(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000840 const FecProtectionParams* delta_fec_params,
841 const FecProtectionParams* key_fec_params,
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000842 uint32_t* sent_video_rate_bps,
843 uint32_t* sent_nack_rate_bps,
844 uint32_t* sent_fec_rate_bps) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000845 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
846 ViEId(engine_id_, channel_id_),
847 "%s, deltaFECRate: %u, key_fecrate: %u, "
848 "delta_use_uep_protection: %d, key_use_uep_protection: %d, "
849 "delta_max_fec_frames: %d, key_max_fec_frames: %d, "
850 "delta_mask_type: %d, key_mask_type: %d, ",
851 __FUNCTION__,
852 delta_fec_params->fec_rate,
853 key_fec_params->fec_rate,
854 delta_fec_params->use_uep_protection,
855 key_fec_params->use_uep_protection,
856 delta_fec_params->max_fec_frames,
857 key_fec_params->max_fec_frames,
858 delta_fec_params->fec_mask_type,
859 key_fec_params->fec_mask_type);
860 if (default_rtp_rtcp_->SetFecParameters(delta_fec_params,
861 key_fec_params) != 0) {
862 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
863 ViEId(engine_id_, channel_id_),
864 "%s: Could not update FEC parameters", __FUNCTION__);
865 }
866 default_rtp_rtcp_->BitrateSent(NULL,
867 sent_video_rate_bps,
868 sent_fec_rate_bps,
869 sent_nack_rate_bps);
870 return 0;
871}
872
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000873int32_t ViEEncoder::SendStatistics(const uint32_t bit_rate,
874 const uint32_t frame_rate) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000875 CriticalSectionScoped cs(callback_cs_.get());
876 if (codec_observer_) {
877 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
878 ViEId(engine_id_, channel_id_), "%s: bitrate %u, framerate %u",
879 __FUNCTION__, bit_rate, frame_rate);
880 codec_observer_->OutgoingRate(channel_id_, frame_rate, bit_rate);
881 }
882 return 0;
883}
884
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000885int32_t ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000886 CriticalSectionScoped cs(callback_cs_.get());
887 if (observer) {
888 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
889 ViEId(engine_id_, channel_id_), "%s: observer added",
890 __FUNCTION__);
891 if (codec_observer_) {
892 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
893 ViEId(engine_id_, channel_id_), "%s: observer already set.",
894 __FUNCTION__);
895 return -1;
896 }
897 codec_observer_ = observer;
898 } else {
899 if (codec_observer_ == NULL) {
900 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
901 ViEId(engine_id_, channel_id_),
902 "%s: observer does not exist.", __FUNCTION__);
903 return -1;
904 }
905 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
906 ViEId(engine_id_, channel_id_), "%s: observer removed",
907 __FUNCTION__);
908 codec_observer_ = NULL;
909 }
910 return 0;
911}
912
913void ViEEncoder::OnReceivedSLI(uint32_t /*ssrc*/,
914 uint8_t picture_id) {
915 picture_id_sli_ = picture_id;
916 has_received_sli_ = true;
917}
918
919void ViEEncoder::OnReceivedRPSI(uint32_t /*ssrc*/,
920 uint64_t picture_id) {
921 picture_id_rpsi_ = picture_id;
922 has_received_rpsi_ = true;
923}
924
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000925void ViEEncoder::OnReceivedIntraFrameRequest(uint32_t ssrc) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000926 // Key frame request from remote side, signal to VCM.
927 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
928 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
justinlin@chromium.orgd474c132013-05-13 22:59:00 +0000929 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000930
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000931 int idx = 0;
932 {
933 CriticalSectionScoped cs(data_cs_.get());
934 std::map<unsigned int, int>::iterator stream_it = ssrc_streams_.find(ssrc);
935 if (stream_it == ssrc_streams_.end()) {
mflodman@webrtc.orgac094232012-12-20 09:26:17 +0000936 LOG_F(LS_WARNING) << "ssrc not found: " << ssrc << ", map size "
937 << ssrc_streams_.size();
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000938 return;
939 }
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000940 std::map<unsigned int, int64_t>::iterator time_it =
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000941 time_last_intra_request_ms_.find(ssrc);
942 if (time_it == time_last_intra_request_ms_.end()) {
943 time_last_intra_request_ms_[ssrc] = 0;
944 }
945
pbos@webrtc.org67879bc2013-04-09 13:41:51 +0000946 int64_t now = TickTime::MillisecondTimestamp();
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000947 if (time_last_intra_request_ms_[ssrc] + kViEMinKeyRequestIntervalMs > now) {
948 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
949 ViEId(engine_id_, channel_id_),
950 "%s: Not encoding new intra due to timing", __FUNCTION__);
951 return;
952 }
953 time_last_intra_request_ms_[ssrc] = now;
954 idx = stream_it->second;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000955 }
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000956 // Release the critsect before triggering key frame.
957 vcm_.IntraFrameRequest(idx);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000958}
959
960void ViEEncoder::OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {
mflodman@webrtc.orgb6d9cfc2012-10-25 11:30:29 +0000961 CriticalSectionScoped cs(data_cs_.get());
962 std::map<unsigned int, int>::iterator it = ssrc_streams_.find(old_ssrc);
963 if (it == ssrc_streams_.end()) {
964 return;
965 }
966
967 ssrc_streams_[new_ssrc] = it->second;
968 ssrc_streams_.erase(it);
969
970 std::map<unsigned int, int64_t>::iterator time_it =
971 time_last_intra_request_ms_.find(old_ssrc);
972 int64_t last_intra_request_ms = 0;
973 if (time_it != time_last_intra_request_ms_.end()) {
974 last_intra_request_ms = time_it->second;
975 time_last_intra_request_ms_.erase(time_it);
976 }
977 time_last_intra_request_ms_[new_ssrc] = last_intra_request_ms;
978}
979
980bool ViEEncoder::SetSsrcs(const std::list<unsigned int>& ssrcs) {
981 VideoCodec codec;
982 if (vcm_.SendCodec(&codec) != 0)
983 return false;
984
985 if (codec.numberOfSimulcastStreams > 0 &&
986 ssrcs.size() != codec.numberOfSimulcastStreams) {
987 return false;
988 }
989
990 CriticalSectionScoped cs(data_cs_.get());
991 ssrc_streams_.clear();
992 time_last_intra_request_ms_.clear();
993 int idx = 0;
994 for (std::list<unsigned int>::const_iterator it = ssrcs.begin();
995 it != ssrcs.end(); ++it, ++idx) {
996 unsigned int ssrc = *it;
997 ssrc_streams_[ssrc] = idx;
998 }
999 return true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001000}
1001
1002// Called from ViEBitrateObserver.
1003void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps,
1004 const uint8_t fraction_lost,
1005 const uint32_t round_trip_time_ms) {
1006 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1007 ViEId(engine_id_, channel_id_),
1008 "%s(bitrate_bps: %u, fraction_lost: %u, rtt_ms: %u",
1009 __FUNCTION__, bitrate_bps, fraction_lost, round_trip_time_ms);
1010
stefan@webrtc.org72e204a2013-03-18 17:00:51 +00001011 vcm_.SetChannelParameters(bitrate_bps, fraction_lost, round_trip_time_ms);
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +00001012 int bitrate_kbps = bitrate_bps / 1000;
stefan@webrtc.org69f76052013-06-17 12:53:37 +00001013 VideoCodec send_codec;
1014 if (vcm_.SendCodec(&send_codec) != 0) {
1015 return;
1016 }
1017 int pad_up_to_bitrate = std::min(bitrate_kbps,
1018 static_cast<int>(send_codec.maxBitrate));
1019 paced_sender_->UpdateBitrate(bitrate_kbps, pad_up_to_bitrate);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001020 default_rtp_rtcp_->SetTargetSendBitrate(bitrate_bps);
1021}
1022
pwestin@webrtc.org5e87b5f2012-11-13 21:12:39 +00001023PacedSender* ViEEncoder::GetPacedSender() {
1024 return paced_sender_.get();
1025}
1026
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001027int32_t ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001028 CriticalSectionScoped cs(callback_cs_.get());
1029 if (effect_filter == NULL) {
1030 if (effect_filter_ == NULL) {
1031 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1032 ViEId(engine_id_, channel_id_), "%s: no effect filter added",
1033 __FUNCTION__);
1034 return -1;
1035 }
1036 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1037 ViEId(engine_id_, channel_id_), "%s: deregister effect filter",
1038 __FUNCTION__);
1039 } else {
1040 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1041 ViEId(engine_id_, channel_id_), "%s: register effect",
1042 __FUNCTION__);
1043 if (effect_filter_) {
1044 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1045 ViEId(engine_id_, channel_id_),
1046 "%s: effect filter already added ", __FUNCTION__);
1047 return -1;
1048 }
1049 }
1050 effect_filter_ = effect_filter;
1051 return 0;
1052}
1053
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001054int ViEEncoder::StartDebugRecording(const char* fileNameUTF8) {
1055 return vcm_.StartDebugRecording(fileNameUTF8);
1056}
1057
1058int ViEEncoder::StopDebugRecording() {
1059 return vcm_.StopDebugRecording();
1060}
1061
1062QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessingModule* vpm)
1063 : vpm_(vpm) {
1064}
1065
1066QMVideoSettingsCallback::~QMVideoSettingsCallback() {
1067}
1068
pbos@webrtc.org67879bc2013-04-09 13:41:51 +00001069int32_t QMVideoSettingsCallback::SetVideoQMSettings(
1070 const uint32_t frame_rate,
1071 const uint32_t width,
1072 const uint32_t height) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001073 return vpm_->SetTargetResolution(width, height, frame_rate);
1074}
1075
1076} // namespace webrtc