2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/video_engine/vie_encoder.h"
17 #include "webrtc/common_video/interface/video_image.h"
18 #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"
25 #include "webrtc/modules/video_coding/main/source/encoded_frame.h"
26 #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"
33 #include "webrtc/frame_callback.h"
34 #include "webrtc/video_engine/vie_defines.h"
38 // Pace in kbits/s until we receive first estimate.
39 static const int kInitialPace = 2000;
41 // 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.
46 static const float kPaceMultiplier = 2.5f;
48 // Margin on when we pause the encoder when the pacing buffer overflows relative
49 // to the configured buffer delay.
50 static const float kEncoderPausePacerMargin = 2.0f;
52 // Don't stop the encoder unless the delay is above this configured value.
53 static const int kMinPacingDelayMs = 200;
55 // 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.
59 static const int kTransmissionMaxBitrateMultiplier = 2;
61 static const float kStopPaddingThresholdMs = 2000;
63 std::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;
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;
78 stream_bitrates[i] = stream_configs[i].maxBitrate * 1000;
80 bitrate_remainder -= stream_bitrates[i];
82 return stream_bitrates;
85 class QMVideoSettingsCallback : public VCMQMSettingsCallback {
87 explicit QMVideoSettingsCallback(VideoProcessingModule* vpm);
89 ~QMVideoSettingsCallback();
91 // Update VPM with QM (quality modes: frame size & frame rate) settings.
92 int32_t SetVideoQMSettings(const uint32_t frame_rate,
94 const uint32_t height);
97 VideoProcessingModule* vpm_;
100 class ViEBitrateObserver : public BitrateObserver {
102 explicit ViEBitrateObserver(ViEEncoder* owner)
105 virtual ~ViEBitrateObserver() {}
106 // 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);
116 class ViEPacedSenderCallback : public PacedSender::Callback {
118 explicit ViEPacedSenderCallback(ViEEncoder* owner)
121 virtual ~ViEPacedSenderCallback() {}
122 virtual bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number,
123 int64_t capture_time_ms, bool retransmission) {
124 return owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms,
127 virtual int TimeToSendPadding(int bytes) {
128 return owner_->TimeToSendPadding(bytes);
134 ViEEncoder::ViEEncoder(int32_t engine_id,
136 uint32_t number_of_cores,
137 const Config& config,
138 ProcessThread& module_process_thread,
139 BitrateController* bitrate_controller)
140 : engine_id_(engine_id),
141 channel_id_(channel_id),
142 number_of_cores_(number_of_cores),
143 vcm_(*webrtc::VideoCodingModule::Create(ViEModuleId(engine_id,
145 vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
147 callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
148 data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
149 bitrate_controller_(bitrate_controller),
150 time_of_last_incoming_frame_ms_(0),
151 send_padding_(false),
153 network_is_transmitting_(true),
154 encoder_paused_(false),
155 encoder_paused_and_dropped_frame_(false),
157 nack_enabled_(false),
158 codec_observer_(NULL),
159 effect_filter_(NULL),
160 module_process_thread_(module_process_thread),
161 has_received_sli_(false),
163 has_received_rpsi_(false),
166 video_suspended_(false),
167 pre_encode_callback_(NULL) {
168 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
169 ViEId(engine_id, channel_id),
170 "%s(engine_id: %d) 0x%p - Constructor", __FUNCTION__, engine_id,
173 RtpRtcp::Configuration configuration;
174 configuration.id = ViEModuleId(engine_id_, channel_id_);
175 configuration.audio = false; // Video.
177 default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
178 bitrate_observer_.reset(new ViEBitrateObserver(this));
179 pacing_callback_.reset(new ViEPacedSenderCallback(this));
181 new PacedSender(pacing_callback_.get(), kInitialPace, kPaceMultiplier));
184 bool ViEEncoder::Init() {
185 if (vcm_.InitializeSender() != 0) {
186 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
187 ViEId(engine_id_, channel_id_),
188 "%s InitializeSender failure", __FUNCTION__);
191 vpm_.EnableTemporalDecimation(true);
193 // Enable/disable content analysis: off by default for now.
194 vpm_.EnableContentAnalysis(false);
196 if (module_process_thread_.RegisterModule(&vcm_) != 0 ||
197 module_process_thread_.RegisterModule(default_rtp_rtcp_.get()) != 0 ||
198 module_process_thread_.RegisterModule(paced_sender_.get()) != 0) {
199 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
200 ViEId(engine_id_, channel_id_),
201 "%s RegisterModule failure", __FUNCTION__);
207 qm_callback_ = new QMVideoSettingsCallback(&vpm_);
209 #ifdef VIDEOCODEC_VP8
210 VideoCodec video_codec;
211 if (vcm_.Codec(webrtc::kVideoCodecVP8, &video_codec) != VCM_OK) {
212 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
213 ViEId(engine_id_, channel_id_),
214 "%s Codec failure", __FUNCTION__);
217 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
218 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
219 default_rtp_rtcp_->MaxDataPayloadLength()) != 0) {
220 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
221 ViEId(engine_id_, channel_id_),
222 "%s RegisterSendCodec failure", __FUNCTION__);
225 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
226 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
227 ViEId(engine_id_, channel_id_),
228 "%s RegisterSendPayload failure", __FUNCTION__);
232 VideoCodec video_codec;
233 if (vcm_.Codec(webrtc::kVideoCodecI420, &video_codec) == VCM_OK) {
234 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
235 vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
236 default_rtp_rtcp_->MaxDataPayloadLength());
237 default_rtp_rtcp_->RegisterSendPayload(video_codec);
243 if (vcm_.RegisterTransportCallback(this) != 0) {
244 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
245 ViEId(engine_id_, channel_id_),
246 "ViEEncoder: VCM::RegisterTransportCallback failure");
249 if (vcm_.RegisterSendStatisticsCallback(this) != 0) {
250 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
251 ViEId(engine_id_, channel_id_),
252 "ViEEncoder: VCM::RegisterSendStatisticsCallback failure");
255 if (vcm_.RegisterVideoQMCallback(qm_callback_) != 0) {
256 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
257 ViEId(engine_id_, channel_id_),
258 "VCM::RegisterQMCallback failure");
264 ViEEncoder::~ViEEncoder() {
265 WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo,
266 ViEId(engine_id_, channel_id_),
267 "ViEEncoder Destructor 0x%p, engine_id: %d", this, engine_id_);
268 if (bitrate_controller_) {
269 bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
271 module_process_thread_.DeRegisterModule(&vcm_);
272 module_process_thread_.DeRegisterModule(&vpm_);
273 module_process_thread_.DeRegisterModule(default_rtp_rtcp_.get());
274 module_process_thread_.DeRegisterModule(paced_sender_.get());
275 VideoCodingModule::Destroy(&vcm_);
276 VideoProcessingModule::Destroy(&vpm_);
280 int ViEEncoder::Owner() const {
284 void ViEEncoder::SetNetworkTransmissionState(bool is_transmitting) {
285 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
286 ViEId(engine_id_, channel_id_),
287 "%s(%s)", __FUNCTION__,
288 is_transmitting ? "transmitting" : "not transmitting");
290 CriticalSectionScoped cs(data_cs_.get());
291 network_is_transmitting_ = is_transmitting;
293 if (is_transmitting) {
294 paced_sender_->Resume();
296 paced_sender_->Pause();
300 void ViEEncoder::Pause() {
301 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
302 ViEId(engine_id_, channel_id_),
304 CriticalSectionScoped cs(data_cs_.get());
305 encoder_paused_ = true;
308 void ViEEncoder::Restart() {
309 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
310 ViEId(engine_id_, channel_id_),
312 CriticalSectionScoped cs(data_cs_.get());
313 encoder_paused_ = false;
316 uint8_t ViEEncoder::NumberOfCodecs() {
317 return vcm_.NumberOfCodecs();
320 int32_t ViEEncoder::GetCodec(uint8_t list_index, VideoCodec* video_codec) {
321 if (vcm_.Codec(list_index, video_codec) != 0) {
322 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
323 ViEId(engine_id_, channel_id_), "%s: Could not get codec",
330 int32_t ViEEncoder::RegisterExternalEncoder(webrtc::VideoEncoder* encoder,
332 bool internal_source) {
333 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
334 ViEId(engine_id_, channel_id_), "%s: pltype %u", __FUNCTION__,
340 if (vcm_.RegisterExternalEncoder(encoder, pl_type, internal_source) !=
342 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
343 ViEId(engine_id_, channel_id_),
344 "Could not register external encoder");
350 int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) {
351 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
352 ViEId(engine_id_, channel_id_),
353 "%s: pltype %u", __FUNCTION__, pl_type);
355 webrtc::VideoCodec current_send_codec;
356 if (vcm_.SendCodec(¤t_send_codec) == VCM_OK) {
357 uint32_t current_bitrate_bps = 0;
358 if (vcm_.Bitrate(¤t_bitrate_bps) != 0) {
359 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
360 ViEId(engine_id_, channel_id_),
361 "Failed to get the current encoder target bitrate.");
363 current_send_codec.startBitrate = (current_bitrate_bps + 500) / 1000;
366 if (vcm_.RegisterExternalEncoder(NULL, pl_type) != VCM_OK) {
367 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
368 ViEId(engine_id_, channel_id_),
369 "Could not deregister external encoder");
373 // If the external encoder is the current send codec, use vcm internal
375 if (current_send_codec.plType == pl_type) {
376 uint16_t max_data_payload_length =
377 default_rtp_rtcp_->MaxDataPayloadLength();
378 send_padding_ = current_send_codec.numberOfSimulcastStreams > 1;
379 if (vcm_.RegisterSendCodec(¤t_send_codec, number_of_cores_,
380 max_data_payload_length) != VCM_OK) {
381 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
382 ViEId(engine_id_, channel_id_),
383 "Could not use internal encoder");
390 int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
391 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
392 ViEId(engine_id_, channel_id_),
393 "%s: CodecType: %d, width: %u, height: %u", __FUNCTION__,
394 video_codec.codecType, video_codec.width, video_codec.height);
395 // Setting target width and height for VPM.
396 if (vpm_.SetTargetResolution(video_codec.width, video_codec.height,
397 video_codec.maxFramerate) != VPM_OK) {
398 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
399 ViEId(engine_id_, channel_id_),
400 "Could not set VPM target dimensions");
404 if (default_rtp_rtcp_->RegisterSendPayload(video_codec) != 0) {
405 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
406 ViEId(engine_id_, channel_id_),
407 "Could register RTP module video payload");
410 // Convert from kbps to bps.
411 std::vector<uint32_t> stream_bitrates = AllocateStreamBitrates(
412 video_codec.startBitrate * 1000,
413 video_codec.simulcastStream,
414 video_codec.numberOfSimulcastStreams);
415 default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
417 uint16_t max_data_payload_length =
418 default_rtp_rtcp_->MaxDataPayloadLength();
420 send_padding_ = video_codec.numberOfSimulcastStreams > 1;
421 if (vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
422 max_data_payload_length) != VCM_OK) {
423 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
424 ViEId(engine_id_, channel_id_),
425 "Could not register send codec");
429 // Set this module as sending right away, let the slave module in the channel
430 // start and stop sending.
431 if (default_rtp_rtcp_->Sending() == false) {
432 if (default_rtp_rtcp_->SetSendingStatus(true) != 0) {
433 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
434 ViEId(engine_id_, channel_id_),
435 "Could start RTP module sending");
439 bitrate_controller_->SetBitrateObserver(bitrate_observer_.get(),
440 video_codec.startBitrate * 1000,
441 video_codec.minBitrate * 1000,
442 kTransmissionMaxBitrateMultiplier *
443 video_codec.maxBitrate * 1000);
448 int32_t ViEEncoder::GetEncoder(VideoCodec* video_codec) {
449 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
450 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
452 if (vcm_.SendCodec(video_codec) != 0) {
453 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
454 ViEId(engine_id_, channel_id_),
455 "Could not get VCM send codec");
461 int32_t ViEEncoder::GetCodecConfigParameters(
462 unsigned char config_parameters[kConfigParameterSize],
463 unsigned char& config_parameters_size) {
464 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
465 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
467 int32_t num_parameters =
468 vcm_.CodecConfigParameters(config_parameters, kConfigParameterSize);
469 if (num_parameters <= 0) {
470 config_parameters_size = 0;
471 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
472 ViEId(engine_id_, channel_id_),
473 "Could not get config parameters");
476 config_parameters_size = static_cast<unsigned char>(num_parameters);
480 int32_t ViEEncoder::ScaleInputImage(bool enable) {
481 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
482 ViEId(engine_id_, channel_id_), "%s(enable %d)", __FUNCTION__,
485 VideoFrameResampling resampling_mode = kFastRescaling;
486 if (enable == true) {
487 // kInterpolation is currently not supported.
488 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
489 ViEId(engine_id_, channel_id_), "%s not supported",
490 __FUNCTION__, enable);
493 vpm_.SetInputFrameResampleMode(resampling_mode);
498 bool ViEEncoder::TimeToSendPacket(uint32_t ssrc,
499 uint16_t sequence_number,
500 int64_t capture_time_ms,
501 bool retransmission) {
502 return default_rtp_rtcp_->TimeToSendPacket(ssrc, sequence_number,
503 capture_time_ms, retransmission);
506 int ViEEncoder::TimeToSendPadding(int bytes) {
509 CriticalSectionScoped cs(data_cs_.get());
510 send_padding = send_padding_ || video_suspended_;
513 return default_rtp_rtcp_->TimeToSendPadding(bytes);
518 bool ViEEncoder::EncoderPaused() const {
519 // Pause video if paused by caller or as long as the network is down or the
520 // pacer queue has grown too large in buffered mode.
521 if (encoder_paused_) {
524 if (target_delay_ms_ > 0) {
526 // TODO(pwestin): Workaround until nack is configured as a time and not
527 // number of packets.
528 return paced_sender_->QueueInMs() >=
529 std::max(static_cast<int>(target_delay_ms_ * kEncoderPausePacerMargin),
532 return !network_is_transmitting_;
535 RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
536 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
537 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
539 return default_rtp_rtcp_.get();
542 void ViEEncoder::DeliverFrame(int id,
543 I420VideoFrame* video_frame,
545 const uint32_t CSRC[kRtpCsrcSize]) {
546 WEBRTC_TRACE(webrtc::kTraceStream,
548 ViEId(engine_id_, channel_id_),
549 "%s: %llu", __FUNCTION__,
550 video_frame->timestamp());
552 CriticalSectionScoped cs(data_cs_.get());
553 time_of_last_incoming_frame_ms_ = TickTime::MillisecondTimestamp();
554 if (default_rtp_rtcp_->SendingMedia() == false) {
555 // We've paused or we have no channels attached, don't encode.
558 if (EncoderPaused()) {
559 if (!encoder_paused_and_dropped_frame_) {
560 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "EncoderPaused", this);
562 encoder_paused_and_dropped_frame_ = true;
565 if (encoder_paused_and_dropped_frame_) {
566 TRACE_EVENT_ASYNC_END0("webrtc", "EncoderPaused", this);
568 encoder_paused_and_dropped_frame_ = false;
571 // Convert render time, in ms, to RTP timestamp.
572 const int kMsToRtpTimestamp = 90;
573 const uint32_t time_stamp =
575 static_cast<uint32_t>(video_frame->render_time_ms());
577 TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame->render_time_ms(),
579 video_frame->set_timestamp(time_stamp);
581 CriticalSectionScoped cs(callback_cs_.get());
582 if (effect_filter_) {
583 unsigned int length = CalcBufferSize(kI420,
584 video_frame->width(),
585 video_frame->height());
586 scoped_array<uint8_t> video_buffer(new uint8_t[length]);
587 ExtractBuffer(*video_frame, length, video_buffer.get());
588 effect_filter_->Transform(length,
590 video_frame->timestamp(),
591 video_frame->width(),
592 video_frame->height());
596 // Make sure the CSRC list is correct.
598 uint32_t tempCSRC[kRtpCsrcSize];
599 for (int i = 0; i < num_csrcs; i++) {
601 tempCSRC[i] = default_rtp_rtcp_->SSRC();
603 tempCSRC[i] = CSRC[i];
606 default_rtp_rtcp_->SetCSRCs(tempCSRC, (uint8_t) num_csrcs);
608 // Pass frame via preprocessor.
609 I420VideoFrame* decimated_frame = NULL;
610 const int ret = vpm_.PreprocessFrame(*video_frame, &decimated_frame);
616 WEBRTC_TRACE(webrtc::kTraceError,
618 ViEId(engine_id_, channel_id_),
619 "%s: Error preprocessing frame %u", __FUNCTION__,
620 video_frame->timestamp());
623 // Frame was not sampled => use original.
624 if (decimated_frame == NULL) {
625 decimated_frame = video_frame;
629 CriticalSectionScoped cs(callback_cs_.get());
630 if (pre_encode_callback_)
631 pre_encode_callback_->FrameCallback(decimated_frame);
634 #ifdef VIDEOCODEC_VP8
635 if (vcm_.SendCodec() == webrtc::kVideoCodecVP8) {
636 webrtc::CodecSpecificInfo codec_specific_info;
637 codec_specific_info.codecType = webrtc::kVideoCodecVP8;
638 codec_specific_info.codecSpecific.VP8.hasReceivedRPSI =
640 codec_specific_info.codecSpecific.VP8.hasReceivedSLI =
642 codec_specific_info.codecSpecific.VP8.pictureIdRPSI =
644 codec_specific_info.codecSpecific.VP8.pictureIdSLI =
646 has_received_sli_ = false;
647 has_received_rpsi_ = false;
649 if (vcm_.AddVideoFrame(*decimated_frame,
650 vpm_.ContentMetrics(),
651 &codec_specific_info) != VCM_OK) {
652 WEBRTC_TRACE(webrtc::kTraceError,
654 ViEId(engine_id_, channel_id_),
655 "%s: Error encoding frame %u", __FUNCTION__,
656 video_frame->timestamp());
661 if (vcm_.AddVideoFrame(*decimated_frame) != VCM_OK) {
662 WEBRTC_TRACE(webrtc::kTraceError,
664 ViEId(engine_id_, channel_id_),
665 "%s: Error encoding frame %u", __FUNCTION__,
666 video_frame->timestamp());
670 void ViEEncoder::DelayChanged(int id, int frame_delay) {
671 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
672 ViEId(engine_id_, channel_id_), "%s: %u", __FUNCTION__,
675 default_rtp_rtcp_->SetCameraDelay(frame_delay);
678 int ViEEncoder::GetPreferedFrameSettings(int* width,
681 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
682 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
684 webrtc::VideoCodec video_codec;
685 memset(&video_codec, 0, sizeof(video_codec));
686 if (vcm_.SendCodec(&video_codec) != VCM_OK) {
687 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
688 ViEId(engine_id_, channel_id_),
689 "Could not get VCM send codec");
693 *width = video_codec.width;
694 *height = video_codec.height;
695 *frame_rate = video_codec.maxFramerate;
699 int ViEEncoder::SendKeyFrame() {
700 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
701 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
702 return vcm_.IntraFrameRequest(0);
705 int32_t ViEEncoder::SendCodecStatistics(
706 uint32_t* num_key_frames, uint32_t* num_delta_frames) {
707 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
708 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
710 webrtc::VCMFrameCount sent_frames;
711 if (vcm_.SentFrameCount(sent_frames) != VCM_OK) {
712 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
713 ViEId(engine_id_, channel_id_),
714 "%s: Could not get sent frame information", __FUNCTION__);
717 *num_key_frames = sent_frames.numKeyFrames;
718 *num_delta_frames = sent_frames.numDeltaFrames;
722 int32_t ViEEncoder::EstimatedSendBandwidth(
723 uint32_t* available_bandwidth) const {
724 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
727 if (!bitrate_controller_->AvailableBandwidth(available_bandwidth)) {
733 int ViEEncoder::CodecTargetBitrate(uint32_t* bitrate) const {
734 WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
736 if (vcm_.Bitrate(bitrate) != 0)
741 int32_t ViEEncoder::UpdateProtectionMethod(bool enable_nack) {
742 bool fec_enabled = false;
743 uint8_t dummy_ptype_red = 0;
744 uint8_t dummy_ptypeFEC = 0;
746 // Updated protection method to VCM to get correct packetization sizes.
747 // FEC has larger overhead than NACK -> set FEC if used.
748 int32_t error = default_rtp_rtcp_->GenericFECStatus(fec_enabled,
754 if (fec_enabled_ == fec_enabled && nack_enabled_ == enable_nack) {
755 // No change needed, we're already in correct state.
758 fec_enabled_ = fec_enabled;
759 nack_enabled_ = enable_nack;
761 // Set Video Protection for VCM.
762 if (fec_enabled && nack_enabled_) {
763 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, true);
765 vcm_.SetVideoProtection(webrtc::kProtectionFEC, fec_enabled_);
766 vcm_.SetVideoProtection(webrtc::kProtectionNackSender, nack_enabled_);
767 vcm_.SetVideoProtection(webrtc::kProtectionNackFEC, false);
770 if (fec_enabled_ || nack_enabled_) {
771 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
772 ViEId(engine_id_, channel_id_), "%s: FEC status ",
773 __FUNCTION__, fec_enabled);
774 vcm_.RegisterProtectionCallback(this);
775 // The send codec must be registered to set correct MTU.
776 webrtc::VideoCodec codec;
777 if (vcm_.SendCodec(&codec) == 0) {
778 uint16_t max_pay_load = default_rtp_rtcp_->MaxDataPayloadLength();
779 uint32_t current_bitrate_bps = 0;
780 if (vcm_.Bitrate(¤t_bitrate_bps) != 0) {
781 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo,
782 ViEId(engine_id_, channel_id_),
783 "Failed to get the current encoder target bitrate.");
785 // Convert to start bitrate in kbps.
786 codec.startBitrate = (current_bitrate_bps + 500) / 1000;
787 if (vcm_.RegisterSendCodec(&codec, number_of_cores_, max_pay_load) != 0) {
788 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
789 ViEId(engine_id_, channel_id_),
790 "%s: Failed to update Sendcodec when enabling FEC",
791 __FUNCTION__, fec_enabled);
797 // FEC and NACK are disabled.
798 vcm_.RegisterProtectionCallback(NULL);
803 void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) {
805 CriticalSectionScoped cs(data_cs_.get());
806 target_delay_ms_ = target_delay_ms;
808 if (target_delay_ms > 0) {
809 // Disable external frame-droppers.
810 vcm_.EnableFrameDropper(false);
811 vpm_.EnableTemporalDecimation(false);
812 // We don't put any limits on the pacer queue when running in buffered mode
813 // since the encoder will be paused if the queue grow too large.
814 paced_sender_->set_max_queue_length_ms(-1);
816 // Real-time mode - enable frame droppers.
817 vpm_.EnableTemporalDecimation(true);
818 vcm_.EnableFrameDropper(true);
819 paced_sender_->set_max_queue_length_ms(
820 PacedSender::kDefaultMaxQueueLengthMs);
824 int32_t ViEEncoder::SendData(
825 const FrameType frame_type,
826 const uint8_t payload_type,
827 const uint32_t time_stamp,
828 int64_t capture_time_ms,
829 const uint8_t* payload_data,
830 const uint32_t payload_size,
831 const webrtc::RTPFragmentationHeader& fragmentation_header,
832 const RTPVideoHeader* rtp_video_hdr) {
833 // New encoded data, hand over to the rtp module.
834 return default_rtp_rtcp_->SendOutgoingData(frame_type,
840 &fragmentation_header,
844 int32_t ViEEncoder::ProtectionRequest(
845 const FecProtectionParams* delta_fec_params,
846 const FecProtectionParams* key_fec_params,
847 uint32_t* sent_video_rate_bps,
848 uint32_t* sent_nack_rate_bps,
849 uint32_t* sent_fec_rate_bps) {
850 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
851 ViEId(engine_id_, channel_id_),
852 "%s, deltaFECRate: %u, key_fecrate: %u, "
853 "delta_use_uep_protection: %d, key_use_uep_protection: %d, "
854 "delta_max_fec_frames: %d, key_max_fec_frames: %d, "
855 "delta_mask_type: %d, key_mask_type: %d, ",
857 delta_fec_params->fec_rate,
858 key_fec_params->fec_rate,
859 delta_fec_params->use_uep_protection,
860 key_fec_params->use_uep_protection,
861 delta_fec_params->max_fec_frames,
862 key_fec_params->max_fec_frames,
863 delta_fec_params->fec_mask_type,
864 key_fec_params->fec_mask_type);
865 if (default_rtp_rtcp_->SetFecParameters(delta_fec_params,
866 key_fec_params) != 0) {
867 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
868 ViEId(engine_id_, channel_id_),
869 "%s: Could not update FEC parameters", __FUNCTION__);
871 default_rtp_rtcp_->BitrateSent(NULL,
878 int32_t ViEEncoder::SendStatistics(const uint32_t bit_rate,
879 const uint32_t frame_rate) {
880 CriticalSectionScoped cs(callback_cs_.get());
881 if (codec_observer_) {
882 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
883 ViEId(engine_id_, channel_id_), "%s: bitrate %u, framerate %u",
884 __FUNCTION__, bit_rate, frame_rate);
885 codec_observer_->OutgoingRate(channel_id_, frame_rate, bit_rate);
890 int32_t ViEEncoder::RegisterCodecObserver(ViEEncoderObserver* observer) {
891 CriticalSectionScoped cs(callback_cs_.get());
893 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
894 ViEId(engine_id_, channel_id_), "%s: observer added",
896 if (codec_observer_) {
897 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
898 ViEId(engine_id_, channel_id_), "%s: observer already set.",
902 codec_observer_ = observer;
904 if (codec_observer_ == NULL) {
905 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
906 ViEId(engine_id_, channel_id_),
907 "%s: observer does not exist.", __FUNCTION__);
910 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
911 ViEId(engine_id_, channel_id_), "%s: observer removed",
913 codec_observer_ = NULL;
918 void ViEEncoder::OnReceivedSLI(uint32_t /*ssrc*/,
919 uint8_t picture_id) {
920 picture_id_sli_ = picture_id;
921 has_received_sli_ = true;
924 void ViEEncoder::OnReceivedRPSI(uint32_t /*ssrc*/,
925 uint64_t picture_id) {
926 picture_id_rpsi_ = picture_id;
927 has_received_rpsi_ = true;
930 void ViEEncoder::OnReceivedIntraFrameRequest(uint32_t ssrc) {
931 // Key frame request from remote side, signal to VCM.
932 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideo,
933 ViEId(engine_id_, channel_id_), "%s", __FUNCTION__);
934 TRACE_EVENT0("webrtc", "OnKeyFrameRequest");
938 CriticalSectionScoped cs(data_cs_.get());
939 std::map<unsigned int, int>::iterator stream_it = ssrc_streams_.find(ssrc);
940 if (stream_it == ssrc_streams_.end()) {
941 LOG_F(LS_WARNING) << "ssrc not found: " << ssrc << ", map size "
942 << ssrc_streams_.size();
945 std::map<unsigned int, int64_t>::iterator time_it =
946 time_last_intra_request_ms_.find(ssrc);
947 if (time_it == time_last_intra_request_ms_.end()) {
948 time_last_intra_request_ms_[ssrc] = 0;
951 int64_t now = TickTime::MillisecondTimestamp();
952 if (time_last_intra_request_ms_[ssrc] + kViEMinKeyRequestIntervalMs > now) {
953 WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo,
954 ViEId(engine_id_, channel_id_),
955 "%s: Not encoding new intra due to timing", __FUNCTION__);
958 time_last_intra_request_ms_[ssrc] = now;
959 idx = stream_it->second;
961 // Release the critsect before triggering key frame.
962 vcm_.IntraFrameRequest(idx);
965 void ViEEncoder::OnLocalSsrcChanged(uint32_t old_ssrc, uint32_t new_ssrc) {
966 CriticalSectionScoped cs(data_cs_.get());
967 std::map<unsigned int, int>::iterator it = ssrc_streams_.find(old_ssrc);
968 if (it == ssrc_streams_.end()) {
972 ssrc_streams_[new_ssrc] = it->second;
973 ssrc_streams_.erase(it);
975 std::map<unsigned int, int64_t>::iterator time_it =
976 time_last_intra_request_ms_.find(old_ssrc);
977 int64_t last_intra_request_ms = 0;
978 if (time_it != time_last_intra_request_ms_.end()) {
979 last_intra_request_ms = time_it->second;
980 time_last_intra_request_ms_.erase(time_it);
982 time_last_intra_request_ms_[new_ssrc] = last_intra_request_ms;
985 bool ViEEncoder::SetSsrcs(const std::list<unsigned int>& ssrcs) {
987 if (vcm_.SendCodec(&codec) != 0)
990 if (codec.numberOfSimulcastStreams > 0 &&
991 ssrcs.size() != codec.numberOfSimulcastStreams) {
995 CriticalSectionScoped cs(data_cs_.get());
996 ssrc_streams_.clear();
997 time_last_intra_request_ms_.clear();
999 for (std::list<unsigned int>::const_iterator it = ssrcs.begin();
1000 it != ssrcs.end(); ++it, ++idx) {
1001 unsigned int ssrc = *it;
1002 ssrc_streams_[ssrc] = idx;
1007 // Called from ViEBitrateObserver.
1008 void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps,
1009 const uint8_t fraction_lost,
1010 const uint32_t round_trip_time_ms) {
1011 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1012 ViEId(engine_id_, channel_id_),
1013 "%s(bitrate_bps: %u, fraction_lost: %u, rtt_ms: %u",
1014 __FUNCTION__, bitrate_bps, fraction_lost, round_trip_time_ms);
1016 vcm_.SetChannelParameters(bitrate_bps, fraction_lost, round_trip_time_ms);
1017 bool video_is_suspended = vcm_.VideoSuspended();
1018 int bitrate_kbps = bitrate_bps / 1000;
1019 VideoCodec send_codec;
1020 if (vcm_.SendCodec(&send_codec) != 0) {
1023 SimulcastStream* stream_configs = send_codec.simulcastStream;
1024 // Allocate the bandwidth between the streams.
1025 std::vector<uint32_t> stream_bitrates = AllocateStreamBitrates(
1028 send_codec.numberOfSimulcastStreams);
1029 // Find the max amount of padding we can allow ourselves to send at this
1030 // point, based on which streams are currently active and what our current
1031 // available bandwidth is.
1032 int max_padding_bitrate_kbps = 0;
1033 int pad_up_to_bitrate_kbps = 0;
1034 if (send_codec.numberOfSimulcastStreams == 0) {
1035 max_padding_bitrate_kbps = send_codec.minBitrate;
1036 pad_up_to_bitrate_kbps = send_codec.minBitrate;
1038 int i = send_codec.numberOfSimulcastStreams - 1;
1039 for (std::vector<uint32_t>::reverse_iterator it = stream_bitrates.rbegin();
1040 it != stream_bitrates.rend(); ++it) {
1042 max_padding_bitrate_kbps = std::min((*it + 500) / 1000,
1043 stream_configs[i].minBitrate);
1048 pad_up_to_bitrate_kbps =
1049 stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate;
1050 for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) {
1051 pad_up_to_bitrate_kbps += stream_configs[i].targetBitrate;
1054 if (video_is_suspended || send_codec.numberOfSimulcastStreams > 1) {
1055 pad_up_to_bitrate_kbps = std::min(bitrate_kbps, pad_up_to_bitrate_kbps);
1057 // Disable padding if only sending one stream and video isn't suspended.
1058 pad_up_to_bitrate_kbps = 0;
1062 // The amount of padding should decay to zero if no frames are being
1064 CriticalSectionScoped cs(data_cs_.get());
1065 int64_t now_ms = TickTime::MillisecondTimestamp();
1066 if (now_ms - time_of_last_incoming_frame_ms_ > kStopPaddingThresholdMs)
1067 max_padding_bitrate_kbps = 0;
1070 paced_sender_->UpdateBitrate(bitrate_kbps,
1071 max_padding_bitrate_kbps,
1072 pad_up_to_bitrate_kbps);
1073 default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
1075 CriticalSectionScoped cs(data_cs_.get());
1076 if (video_suspended_ == video_is_suspended)
1078 video_suspended_ = video_is_suspended;
1080 // State changed, inform codec observer.
1081 if (codec_observer_) {
1082 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1083 ViEId(engine_id_, channel_id_),
1084 "%s: video_suspended_ changed to %i",
1085 __FUNCTION__, video_is_suspended);
1086 codec_observer_->SuspendChange(channel_id_, video_is_suspended);
1090 PacedSender* ViEEncoder::GetPacedSender() {
1091 return paced_sender_.get();
1094 int32_t ViEEncoder::RegisterEffectFilter(ViEEffectFilter* effect_filter) {
1095 CriticalSectionScoped cs(callback_cs_.get());
1096 if (effect_filter == NULL) {
1097 if (effect_filter_ == NULL) {
1098 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1099 ViEId(engine_id_, channel_id_), "%s: no effect filter added",
1103 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1104 ViEId(engine_id_, channel_id_), "%s: deregister effect filter",
1107 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
1108 ViEId(engine_id_, channel_id_), "%s: register effect",
1110 if (effect_filter_) {
1111 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
1112 ViEId(engine_id_, channel_id_),
1113 "%s: effect filter already added ", __FUNCTION__);
1117 effect_filter_ = effect_filter;
1121 int ViEEncoder::StartDebugRecording(const char* fileNameUTF8) {
1122 return vcm_.StartDebugRecording(fileNameUTF8);
1125 int ViEEncoder::StopDebugRecording() {
1126 return vcm_.StopDebugRecording();
1129 void ViEEncoder::SuspendBelowMinBitrate() {
1130 vcm_.SuspendBelowMinBitrate();
1131 bitrate_controller_->EnforceMinBitrate(false);
1134 void ViEEncoder::RegisterPreEncodeCallback(
1135 I420FrameCallback* pre_encode_callback) {
1136 CriticalSectionScoped cs(callback_cs_.get());
1137 pre_encode_callback_ = pre_encode_callback;
1140 void ViEEncoder::DeRegisterPreEncodeCallback() {
1141 CriticalSectionScoped cs(callback_cs_.get());
1142 pre_encode_callback_ = NULL;
1145 void ViEEncoder::RegisterPostEncodeImageCallback(
1146 EncodedImageCallback* post_encode_callback) {
1147 vcm_.RegisterPostEncodeImageCallback(post_encode_callback);
1150 void ViEEncoder::DeRegisterPostEncodeImageCallback() {
1151 vcm_.RegisterPostEncodeImageCallback(NULL);
1154 QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessingModule* vpm)
1158 QMVideoSettingsCallback::~QMVideoSettingsCallback() {
1161 int32_t QMVideoSettingsCallback::SetVideoQMSettings(
1162 const uint32_t frame_rate,
1163 const uint32_t width,
1164 const uint32_t height) {
1165 return vpm_->SetTargetResolution(width, height, frame_rate);
1168 } // namespace webrtc