Utilize bitrate above codec max to protect video.

When estimating that we can send more than the codec max bitrate (under
the assumption that codec max bitrate is good enough for the quality),
we should use additional bitrate so that we can maintain good quality.

Global bitrate caps should still be enforced through bitrate caps (b=AS)
and not codec max bitrates.

BUG=webrtc:5102
R=stefan@webrtc.org

Review URL: https://codereview.webrtc.org/1428473002

Cr-Commit-Position: refs/heads/master@{#10457}
This commit is contained in:
pbos 2015-10-29 15:45:00 -07:00 committed by Commit bot
parent 315dce7ac1
commit 7367463acc
3 changed files with 76 additions and 43 deletions

View File

@ -88,7 +88,7 @@ MediaOptimization::MediaOptimization(Clock* clock)
fraction_lost_(0),
send_statistics_zero_encode_(0),
max_payload_size_(1460),
target_bit_rate_(0),
video_target_bitrate_(0),
incoming_frame_rate_(0),
enable_qm_(false),
encoded_frame_samples_(),
@ -127,7 +127,7 @@ void MediaOptimization::Reset() {
loss_prot_logic_->UpdateFrameRate(incoming_frame_rate_);
loss_prot_logic_->Reset(clock_->TimeInMilliseconds());
send_statistics_zero_encode_ = 0;
target_bit_rate_ = 0;
video_target_bitrate_ = 0;
codec_width_ = 0;
codec_height_ = 0;
user_frame_rate_ = 0;
@ -177,7 +177,7 @@ void MediaOptimization::SetEncodingDataInternal(VideoCodecType send_codec_type,
max_bit_rate_ = max_bit_rate;
send_codec_type_ = send_codec_type;
target_bit_rate_ = target_bitrate;
video_target_bitrate_ = target_bitrate;
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));
@ -204,12 +204,6 @@ uint32_t MediaOptimization::SetTargetRates(
VCMProtectionCallback* protection_callback,
VCMQMSettingsCallback* qmsettings_callback) {
CriticalSectionScoped lock(crit_sect_.get());
// TODO(holmer): Consider putting this threshold only on the video bitrate,
// and not on protection.
if (max_bit_rate_ > 0 &&
target_bitrate > static_cast<uint32_t>(max_bit_rate_)) {
target_bitrate = max_bit_rate_;
}
VCMProtectionMethod* selected_method = loss_prot_logic_->SelectedMethod();
float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f;
loss_prot_logic_->UpdateBitRate(target_bitrate_kbps);
@ -241,7 +235,7 @@ uint32_t MediaOptimization::SetTargetRates(
loss_prot_logic_->UpdateFilteredLossPr(packet_loss_enc);
// Rate cost of the protection methods.
uint32_t protection_overhead_bps = 0;
float protection_overhead_rate = 0.0f;
// Update protection settings, when applicable.
float sent_video_rate_kbps = 0.0f;
@ -273,15 +267,13 @@ uint32_t MediaOptimization::SetTargetRates(
// Estimate the overhead costs of the next second as staying the same
// wrt the source bitrate.
if (sent_total_rate_bps > 0) {
protection_overhead_bps = static_cast<uint32_t>(
target_bitrate *
static_cast<double>(sent_nack_rate_bps + sent_fec_rate_bps) /
sent_total_rate_bps +
0.5);
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_bps > target_bitrate / 2)
protection_overhead_bps = target_bitrate / 2;
if (protection_overhead_rate > 0.5)
protection_overhead_rate = 0.5;
// Get the effective packet loss for encoder ER when applicable. Should be
// passed to encoder via fraction_lost.
@ -290,11 +282,16 @@ uint32_t MediaOptimization::SetTargetRates(
}
// Source coding rate: total rate - protection overhead.
target_bit_rate_ = target_bitrate - protection_overhead_bps;
video_target_bitrate_ = target_bitrate * (1.0 - protection_overhead_rate);
// Cap target video bitrate to codec maximum.
if (max_bit_rate_ > 0 && video_target_bitrate_ > max_bit_rate_) {
video_target_bitrate_ = max_bit_rate_;
}
// Update encoding rates following protection settings.
float target_video_bitrate_kbps =
static_cast<float>(target_bit_rate_) / 1000.0f;
static_cast<float>(video_target_bitrate_) / 1000.0f;
frame_dropper_->SetRates(target_video_bitrate_kbps, incoming_frame_rate_);
if (enable_qm_ && qmsettings_callback) {
@ -314,7 +311,7 @@ uint32_t MediaOptimization::SetTargetRates(
CheckSuspendConditions();
return target_bit_rate_;
return video_target_bitrate_;
}
void MediaOptimization::SetProtectionMethod(VCMProtectionMethodEnum method) {
@ -628,17 +625,18 @@ void MediaOptimization::ProcessIncomingFrameRate(int64_t now) {
}
void MediaOptimization::CheckSuspendConditions() {
// Check conditions for SuspendBelowMinBitrate. |target_bit_rate_| is in bps.
// Check conditions for SuspendBelowMinBitrate. |video_target_bitrate_| is in
// bps.
if (suspension_enabled_) {
if (!video_suspended_) {
// Check if we just went below the threshold.
if (target_bit_rate_ < suspension_threshold_bps_) {
if (video_target_bitrate_ < suspension_threshold_bps_) {
video_suspended_ = true;
}
} else {
// Video is already suspended. Check if we just went over the threshold
// with a margin.
if (target_bit_rate_ >
if (video_target_bitrate_ >
suspension_threshold_bps_ + suspension_window_bps_) {
video_suspended_ = false;
}

View File

@ -121,8 +121,8 @@ class MediaOptimization {
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
// Checks conditions for suspending the video. The method compares
// |target_bit_rate_| with the threshold values for suspension, and changes
// the state of |video_suspended_| accordingly.
// |video_target_bitrate_| with the threshold values for suspension, and
// changes the state of |video_suspended_| accordingly.
void CheckSuspendConditions() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
void SetEncodingDataInternal(VideoCodecType send_codec_type,
@ -155,7 +155,7 @@ class MediaOptimization {
uint32_t send_statistics_[4] GUARDED_BY(crit_sect_);
uint32_t send_statistics_zero_encode_ GUARDED_BY(crit_sect_);
int32_t max_payload_size_ GUARDED_BY(crit_sect_);
int target_bit_rate_ GUARDED_BY(crit_sect_);
int video_target_bitrate_ GUARDED_BY(crit_sect_);
float incoming_frame_rate_ GUARDED_BY(crit_sect_);
int64_t incoming_frame_times_[kFrameCountHistorySize] GUARDED_BY(crit_sect_);
bool enable_qm_ GUARDED_BY(crit_sect_);

View File

@ -65,10 +65,9 @@ TEST_F(TestMediaOptimization, VerifyMuting) {
uint32_t target_bitrate_kbps = 100;
media_opt_.SetTargetRates(target_bitrate_kbps * 1000,
0, // Lossrate.
100,
NULL,
NULL); // RTT in ms.
0, // Lossrate.
100, // RTT in ms.
nullptr, nullptr);
media_opt_.EnableFrameDropper(true);
for (int time = 0; time < 2000; time += frame_time_ms_) {
ASSERT_NO_FATAL_FAILURE(AddFrameAndAdvanceTime(target_bitrate_kbps, false));
@ -76,10 +75,9 @@ TEST_F(TestMediaOptimization, VerifyMuting) {
// Set the target rate below the limit for muting.
media_opt_.SetTargetRates(kThresholdBps - 1000,
0, // Lossrate.
100,
NULL,
NULL); // RTT in ms.
0, // Lossrate.
100, // RTT in ms.
nullptr, nullptr);
// Expect the muter to engage immediately and stay muted.
// Test during 2 seconds.
for (int time = 0; time < 2000; time += frame_time_ms_) {
@ -90,11 +88,10 @@ TEST_F(TestMediaOptimization, VerifyMuting) {
// Set the target above the limit for muting, but not above the
// limit + window.
media_opt_.SetTargetRates(kThresholdBps + 1000,
0, // Lossrate.
100,
NULL,
NULL); // RTT in ms.
// Expect the muter to stay muted.
0, // Lossrate.
100, // RTT in ms.
nullptr, nullptr);
// Expect the muter to stay muted.
// Test during 2 seconds.
for (int time = 0; time < 2000; time += frame_time_ms_) {
EXPECT_TRUE(media_opt_.IsVideoSuspended());
@ -103,10 +100,9 @@ TEST_F(TestMediaOptimization, VerifyMuting) {
// Set the target above limit + window.
media_opt_.SetTargetRates(kThresholdBps + kWindowBps + 1000,
0, // Lossrate.
100,
NULL,
NULL); // RTT in ms.
0, // Lossrate.
100, // RTT in ms.
nullptr, nullptr);
// Expect the muter to disengage immediately.
// Test during 2 seconds.
for (int time = 0; time < 2000; time += frame_time_ms_) {
@ -116,5 +112,44 @@ TEST_F(TestMediaOptimization, VerifyMuting) {
}
}
TEST_F(TestMediaOptimization, ProtectsUsingFecBitrateAboveCodecMax) {
static const int kCodecBitrateBps = 100000;
static const int kMaxBitrateBps = 130000;
class ProtectionCallback : public VCMProtectionCallback {
int ProtectionRequest(const FecProtectionParams* delta_params,
const FecProtectionParams* key_params,
uint32_t* sent_video_rate_bps,
uint32_t* sent_nack_rate_bps,
uint32_t* sent_fec_rate_bps) override {
*sent_video_rate_bps = kCodecBitrateBps;
*sent_nack_rate_bps = 0;
*sent_fec_rate_bps = fec_rate_bps_;
return 0;
}
public:
uint32_t fec_rate_bps_;
} protection_callback;
media_opt_.SetProtectionMethod(kFec);
media_opt_.SetEncodingData(kVideoCodecVP8, kCodecBitrateBps, kCodecBitrateBps,
640, 480, 30, 1, 1000);
// Using 10% of codec bitrate for FEC, should still be able to use all of it.
protection_callback.fec_rate_bps_ = kCodecBitrateBps / 10;
uint32_t target_bitrate = media_opt_.SetTargetRates(
kMaxBitrateBps, 0, 0, &protection_callback, nullptr);
EXPECT_EQ(kCodecBitrateBps, static_cast<int>(target_bitrate));
// Using as much for codec bitrate as fec rate, new target rate should share
// both equally, but only be half of max (since that ceiling should be hit).
protection_callback.fec_rate_bps_ = kCodecBitrateBps;
target_bitrate = media_opt_.SetTargetRates(kMaxBitrateBps, 128, 100,
&protection_callback, nullptr);
EXPECT_EQ(kMaxBitrateBps / 2, static_cast<int>(target_bitrate));
}
} // namespace media_optimization
} // namespace webrtc