| /* |
| * 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 "webrtc/modules/video_coding/protection_bitrate_calculator.h" |
| |
| namespace webrtc { |
| |
| using rtc::CritScope; |
| |
| struct ProtectionBitrateCalculator::EncodedFrameSample { |
| EncodedFrameSample(size_t size_bytes, |
| uint32_t timestamp, |
| int64_t time_complete_ms) |
| : size_bytes(size_bytes), |
| timestamp(timestamp), |
| time_complete_ms(time_complete_ms) {} |
| size_t size_bytes; |
| uint32_t timestamp; |
| int64_t time_complete_ms; |
| }; |
| |
| ProtectionBitrateCalculator::ProtectionBitrateCalculator( |
| Clock* clock, |
| VCMProtectionCallback* protection_callback) |
| : clock_(clock), |
| protection_callback_(protection_callback), |
| loss_prot_logic_(new media_optimization::VCMLossProtectionLogic( |
| clock_->TimeInMilliseconds())), |
| max_payload_size_(1460) {} |
| |
| ProtectionBitrateCalculator::~ProtectionBitrateCalculator(void) { |
| loss_prot_logic_->Release(); |
| } |
| |
| void ProtectionBitrateCalculator::SetEncodingData(uint32_t target_bitrate, |
| uint16_t width, |
| uint16_t height, |
| uint32_t frame_rate, |
| size_t num_temporal_layers, |
| size_t max_payload_size) { |
| CritScope lock(&crit_sect_); |
| // Everything codec specific should be reset here since this means the codec |
| // has changed. |
| float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f; |
| loss_prot_logic_->UpdateBitRate(target_bitrate_kbps); |
| loss_prot_logic_->UpdateFrameRate(static_cast<float>(frame_rate)); |
| loss_prot_logic_->UpdateFrameSize(width, height); |
| loss_prot_logic_->UpdateNumLayers(num_temporal_layers); |
| max_payload_size_ = max_payload_size; |
| } |
| |
| uint32_t ProtectionBitrateCalculator::SetTargetRates( |
| uint32_t estimated_bitrate_bps, |
| int actual_framerate_fps, |
| uint8_t fraction_lost, |
| 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; |
| { |
| CritScope lock(&crit_sect_); |
| |
| 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 50%. |
| if (protection_overhead_rate > 0.5) |
| protection_overhead_rate = 0.5; |
| |
| // Source coding rate: total rate - protection overhead. |
| return estimated_bitrate_bps * (1.0 - protection_overhead_rate); |
| } |
| |
| void ProtectionBitrateCalculator::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; |
| } |
| CritScope lock(&crit_sect_); |
| loss_prot_logic_->SetMethod(method); |
| } |
| |
| void ProtectionBitrateCalculator::UpdateWithEncodedData( |
| const EncodedImage& encoded_image) { |
| const size_t encoded_length = encoded_image._length; |
| CritScope lock(&crit_sect_); |
| if (encoded_length > 0) { |
| const bool delta_frame = encoded_image._frameType != 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)); |
| } |
| } |
| } |
| |
| } // namespace webrtc |