blob: f204b01c7ca215f29f4ae80df6c6e1cebbef6963 [file] [log] [blame]
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/fec_controller_default.h" // NOLINT
#include <stdlib.h>
#include <algorithm>
#include <string>
#include "modules/include/module_fec_types.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
const float kProtectionOverheadRateThreshold = 0.5;
FecControllerDefault::FecControllerDefault(
Clock* clock,
VCMProtectionCallback* protection_callback)
: clock_(clock),
protection_callback_(protection_callback),
loss_prot_logic_(new media_optimization::VCMLossProtectionLogic(
clock_->TimeInMilliseconds())),
max_payload_size_(1460),
overhead_threshold_(GetProtectionOverheadRateThreshold()) {}
FecControllerDefault::FecControllerDefault(Clock* clock)
: clock_(clock),
loss_prot_logic_(new media_optimization::VCMLossProtectionLogic(
clock_->TimeInMilliseconds())),
max_payload_size_(1460),
overhead_threshold_(GetProtectionOverheadRateThreshold()) {}
FecControllerDefault::~FecControllerDefault(void) {
loss_prot_logic_->Release();
}
void FecControllerDefault::SetProtectionCallback(
VCMProtectionCallback* protection_callback) {
protection_callback_ = protection_callback;
}
void FecControllerDefault::SetEncodingData(size_t width,
size_t height,
size_t num_temporal_layers,
size_t max_payload_size) {
MutexLock lock(&mutex_);
loss_prot_logic_->UpdateFrameSize(width, height);
loss_prot_logic_->UpdateNumLayers(num_temporal_layers);
max_payload_size_ = max_payload_size;
}
float FecControllerDefault::GetProtectionOverheadRateThreshold() {
float overhead_threshold =
strtof(webrtc::field_trial::FindFullName(
"WebRTC-ProtectionOverheadRateThreshold")
.c_str(),
nullptr);
if (overhead_threshold > 0 && overhead_threshold <= 1) {
RTC_LOG(LS_INFO) << "ProtectionOverheadRateThreshold is set to "
<< overhead_threshold;
return overhead_threshold;
} else if (overhead_threshold < 0 || overhead_threshold > 1) {
RTC_LOG(LS_WARNING)
<< "ProtectionOverheadRateThreshold field trial is set to "
"an invalid value, expecting a value between (0, 1].";
}
// WebRTC-ProtectionOverheadRateThreshold field trial string is not found, use
// the default value.
return kProtectionOverheadRateThreshold;
}
uint32_t FecControllerDefault::UpdateFecRates(
uint32_t estimated_bitrate_bps,
int actual_framerate_fps,
uint8_t fraction_lost,
std::vector<bool> loss_mask_vector,
int64_t round_trip_time_ms) {
float target_bitrate_kbps =
static_cast<float>(estimated_bitrate_bps) / 1000.0f;
// Sanity check.
if (actual_framerate_fps < 1.0) {
actual_framerate_fps = 1.0;
}
FecProtectionParams delta_fec_params;
FecProtectionParams key_fec_params;
{
MutexLock lock(&mutex_);
loss_prot_logic_->UpdateBitRate(target_bitrate_kbps);
loss_prot_logic_->UpdateRtt(round_trip_time_ms);
// Update frame rate for the loss protection logic class: frame rate should
// be the actual/sent rate.
loss_prot_logic_->UpdateFrameRate(actual_framerate_fps);
// Returns the filtered packet loss, used for the protection setting.
// The filtered loss may be the received loss (no filter), or some
// filtered value (average or max window filter).
// Use max window filter for now.
media_optimization::FilterPacketLossMode filter_mode =
media_optimization::kMaxFilter;
uint8_t packet_loss_enc = loss_prot_logic_->FilteredLoss(
clock_->TimeInMilliseconds(), filter_mode, fraction_lost);
// For now use the filtered loss for computing the robustness settings.
loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc);
if (loss_prot_logic_->SelectedType() == media_optimization::kNone) {
return estimated_bitrate_bps;
}
// Update method will compute the robustness settings for the given
// protection method and the overhead cost
// the protection method is set by the user via SetVideoProtection.
loss_prot_logic_->UpdateMethod();
// Get the bit cost of protection method, based on the amount of
// overhead data actually transmitted (including headers) the last
// second.
// Get the FEC code rate for Key frames (set to 0 when NA).
key_fec_params.fec_rate =
loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorK();
// Get the FEC code rate for Delta frames (set to 0 when NA).
delta_fec_params.fec_rate =
loss_prot_logic_->SelectedMethod()->RequiredProtectionFactorD();
// The RTP module currently requires the same `max_fec_frames` for both
// key and delta frames.
delta_fec_params.max_fec_frames =
loss_prot_logic_->SelectedMethod()->MaxFramesFec();
key_fec_params.max_fec_frames =
loss_prot_logic_->SelectedMethod()->MaxFramesFec();
}
// Set the FEC packet mask type. `kFecMaskBursty` is more effective for
// consecutive losses and little/no packet re-ordering. As we currently
// do not have feedback data on the degree of correlated losses and packet
// re-ordering, we keep default setting to `kFecMaskRandom` for now.
delta_fec_params.fec_mask_type = kFecMaskRandom;
key_fec_params.fec_mask_type = kFecMaskRandom;
// Update protection callback with protection settings.
uint32_t sent_video_rate_bps = 0;
uint32_t sent_nack_rate_bps = 0;
uint32_t sent_fec_rate_bps = 0;
// Rate cost of the protection methods.
float protection_overhead_rate = 0.0f;
// TODO(Marco): Pass FEC protection values per layer.
protection_callback_->ProtectionRequest(
&delta_fec_params, &key_fec_params, &sent_video_rate_bps,
&sent_nack_rate_bps, &sent_fec_rate_bps);
uint32_t sent_total_rate_bps =
sent_video_rate_bps + sent_nack_rate_bps + sent_fec_rate_bps;
// Estimate the overhead costs of the next second as staying the same
// wrt the source bitrate.
if (sent_total_rate_bps > 0) {
protection_overhead_rate =
static_cast<float>(sent_nack_rate_bps + sent_fec_rate_bps) /
sent_total_rate_bps;
}
// Cap the overhead estimate to a threshold, default is 50%.
protection_overhead_rate =
std::min(protection_overhead_rate, overhead_threshold_);
// Source coding rate: total rate - protection overhead.
return estimated_bitrate_bps * (1.0 - protection_overhead_rate);
}
void FecControllerDefault::SetProtectionMethod(bool enable_fec,
bool enable_nack) {
media_optimization::VCMProtectionMethodEnum method(media_optimization::kNone);
if (enable_fec && enable_nack) {
method = media_optimization::kNackFec;
} else if (enable_nack) {
method = media_optimization::kNack;
} else if (enable_fec) {
method = media_optimization::kFec;
}
MutexLock lock(&mutex_);
loss_prot_logic_->SetMethod(method);
}
void FecControllerDefault::UpdateWithEncodedData(
const size_t encoded_image_length,
const VideoFrameType encoded_image_frametype) {
const size_t encoded_length = encoded_image_length;
MutexLock lock(&mutex_);
if (encoded_length > 0) {
const bool delta_frame =
encoded_image_frametype != VideoFrameType::kVideoFrameKey;
if (max_payload_size_ > 0 && encoded_length > 0) {
const float min_packets_per_frame =
encoded_length / static_cast<float>(max_payload_size_);
if (delta_frame) {
loss_prot_logic_->UpdatePacketsPerFrame(min_packets_per_frame,
clock_->TimeInMilliseconds());
} else {
loss_prot_logic_->UpdatePacketsPerFrameKey(
min_packets_per_frame, clock_->TimeInMilliseconds());
}
}
if (!delta_frame && encoded_length > 0) {
loss_prot_logic_->UpdateKeyFrameSize(static_cast<float>(encoded_length));
}
}
}
bool FecControllerDefault::UseLossVectorMask() {
return false;
}
} // namespace webrtc