Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Unified Diff: webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc

Issue 1193513006: In screenshare mode, suppress VP8 bitrate overshoot and increase quality (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
diff --git a/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc b/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
index 63ef227812fc985195ee6fc701f4210e9c43cdab..a219e7c6375adc8924827349428d36dd82184ace 100644
--- a/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
+++ b/webrtc/modules/video_coding/codecs/vp8/screenshare_layers.cc
@@ -11,32 +11,34 @@
#include <stdlib.h>
+#include "webrtc/base/checks.h"
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
namespace webrtc {
-enum { kOneSecond90Khz = 90000 };
+static const int kOneSecond90Khz = 90000;
+static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5;
+static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10;
+static const int kMaxQpDeltaForSync = 8;
const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5;
const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0;
ScreenshareLayers::ScreenshareLayers(int num_temporal_layers,
- uint8_t initial_tl0_pic_idx,
- FrameDropper* tl0_frame_dropper,
- FrameDropper* tl1_frame_dropper)
- : tl0_frame_dropper_(tl0_frame_dropper),
- tl1_frame_dropper_(tl1_frame_dropper),
- number_of_temporal_layers_(num_temporal_layers),
+ uint8_t initial_tl0_pic_idx)
+ : number_of_temporal_layers_(num_temporal_layers),
last_base_layer_sync_(false),
tl0_pic_idx_(initial_tl0_pic_idx),
active_layer_(0),
- framerate_(5),
- last_sync_timestamp_(-1) {
+ last_timestamp_(0),
+ last_sync_timestamp_(0),
+ min_qp_(-1),
+ max_qp_(-1),
+ max_debt_bytes_(0) {
assert(num_temporal_layers > 0);
assert(num_temporal_layers <= 2);
- assert(tl0_frame_dropper && tl1_frame_dropper);
}
int ScreenshareLayers::CurrentLayerId() const {
@@ -49,17 +51,37 @@ int ScreenshareLayers::EncodeFlags(uint32_t timestamp) {
// No flags needed for 1 layer screenshare.
return 0;
}
- CalculateFramerate(timestamp);
+
int flags = 0;
- // Note that ARF on purpose isn't used in this scheme since it is allocated
- // for the last key frame to make key frame caching possible.
- if (tl0_frame_dropper_->DropFrame()) {
- // Must drop TL0, encode TL1 instead.
- if (tl1_frame_dropper_->DropFrame()) {
- // Must drop both TL0 and TL1.
- flags = -1;
+ int temporal_layer;
+
+ if (active_layer_ != -1 &&
+ layers_[active_layer_].state == TemporalLayer::State::kDropped) {
+ temporal_layer = active_layer_;
+ } else {
+ if (layers_[0].debt_bytes_ > max_debt_bytes_) {
+ // Must drop TL0, encode TL1 instead.
+ if (layers_[1].debt_bytes_ > max_debt_bytes_) {
+ // Must drop both TL0 and TL1.
+ temporal_layer = -1;
+ } else {
+ temporal_layer = 1;
+ }
} else {
- active_layer_ = 1;
+ temporal_layer = 0;
+ }
+ }
+
+ switch (temporal_layer) {
+ case 0:
+ // Since this is TL0 we only allow updating and predicting from the LAST
+ // reference frame.
+ flags = VP8_EFLAG_NO_UPD_GF;
+ flags |= VP8_EFLAG_NO_UPD_ARF;
+ flags |= VP8_EFLAG_NO_REF_GF;
+ flags |= VP8_EFLAG_NO_REF_ARF;
+ break;
+ case 1:
if (TimeToSync(timestamp)) {
last_sync_timestamp_ = timestamp;
// Allow predicting from only TL0 to allow participants to switch to the
@@ -75,19 +97,27 @@ int ScreenshareLayers::EncodeFlags(uint32_t timestamp) {
flags |= VP8_EFLAG_NO_UPD_ARF;
flags |= VP8_EFLAG_NO_UPD_LAST;
}
- }
- } else {
- active_layer_ = 0;
- // Since this is TL0 we only allow updating and predicting from the LAST
- // reference frame.
- flags = VP8_EFLAG_NO_UPD_GF;
- flags |= VP8_EFLAG_NO_UPD_ARF;
- flags |= VP8_EFLAG_NO_REF_GF;
- flags |= VP8_EFLAG_NO_REF_ARF;
+ break;
+ case -1:
+ flags = -1;
+ break;
+ default:
+ flags = -1;
+ RTC_NOTREACHED();
}
+
+ active_layer_ = temporal_layer;
+
// Make sure both frame droppers leak out bits.
- tl0_frame_dropper_->Leak(framerate_);
- tl1_frame_dropper_->Leak(framerate_);
+ if (last_timestamp_ != 0) {
+ int64_t ts_diff = timestamp - static_cast<int64_t>(last_timestamp_);
+ if (ts_diff < 0)
+ ts_diff += (1l << 32);
+
+ layers_[0].UpdateDebt(ts_diff / 90);
+ layers_[1].UpdateDebt(ts_diff / 90);
+ }
+ last_timestamp_ = timestamp;
return flags;
}
@@ -95,11 +125,11 @@ bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbit,
int max_bitrate_kbit,
stefan-webrtc 2015/06/18 09:39:02 Should these say kbps instead?
sprang_webrtc 2015/06/18 13:05:02 Done.
int framerate,
vpx_codec_enc_cfg_t* cfg) {
- if (framerate > 0)
- framerate_ = framerate;
+ int avg_frame_size = (bitrate_kbit * 1000) / (8 * framerate);
+ max_debt_bytes_ = 5 * avg_frame_size;
- tl0_frame_dropper_->SetRates(bitrate_kbit, framerate_);
- tl1_frame_dropper_->SetRates(max_bitrate_kbit, framerate_);
+ layers_[0].target_rate_kbps_ = bitrate_kbit;
+ layers_[1].target_rate_kbps_ = max_bitrate_kbit;
if (cfg != nullptr) {
// Calculate a codec target bitrate. This may be higher than TL0, gaining
@@ -109,6 +139,14 @@ bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbit,
double target_bitrate =
std::min(bitrate_kbit * kMaxTL0FpsReduction,
max_bitrate_kbit / kAcceptableTargetOvershoot);
+
+ if (layers_[active_layer_].state != TemporalLayer::State::kQualityBoost) {
+ min_qp_ = cfg->rc_min_quantizer;
+ max_qp_ = cfg->rc_max_quantizer;
+ layers_[0].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 80) / 100);
+ layers_[1].enhanced_max_qp = min_qp_ + (((max_qp_ - min_qp_) * 85) / 100);
stefan-webrtc 2015/06/18 09:39:02 80% more in the lower layer and 85% more in the hi
sprang_webrtc 2015/06/18 13:05:02 Done.
+ }
+
cfg->rc_target_bitrate =
std::max(static_cast<unsigned int>(bitrate_kbit),
static_cast<unsigned int>(target_bitrate + 0.5));
@@ -117,11 +155,22 @@ bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbit,
return true;
}
-void ScreenshareLayers::FrameEncoded(unsigned int size, uint32_t timestamp) {
- if (active_layer_ == 0) {
- tl0_frame_dropper_->Fill(size, true);
+void ScreenshareLayers::FrameEncoded(unsigned int size,
+ uint32_t timestamp,
+ int qp) {
+ if (size == 0) {
+ layers_[active_layer_].state = TemporalLayer::State::kDropped;
+ return;
+ }
+ if (layers_[active_layer_].state == TemporalLayer::State::kDropped) {
+ layers_[active_layer_].state = TemporalLayer::State::kQualityBoost;
stefan-webrtc 2015/06/18 09:39:02 This means we always boost quality after a drop? D
sprang_webrtc 2015/06/18 13:05:02 The rate control will be reset to start at max qp,
}
- tl1_frame_dropper_->Fill(size, true);
+
+ if (qp != -1)
+ layers_[active_layer_].last_qp = qp;
+ if (active_layer_ == 0)
+ layers_[0].debt_bytes_ += size;
+ layers_[1].debt_bytes_ += size;
}
void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync,
@@ -152,25 +201,45 @@ void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync,
bool ScreenshareLayers::TimeToSync(uint32_t timestamp) const {
const uint32_t timestamp_diff = timestamp - last_sync_timestamp_;
- return last_sync_timestamp_ < 0 || timestamp_diff > kOneSecond90Khz;
+ if (last_sync_timestamp_ == 0 || timestamp_diff > kMaxTimeBetweenSyncs)
+ return true;
+ if (layers_[0].last_qp == -1 || layers_[1].last_qp == -1)
stefan-webrtc 2015/06/18 09:39:02 This means that the first frame should be a sync f
sprang_webrtc 2015/06/18 13:05:02 Done.
+ return true;
+ if (timestamp_diff < kMinTimeBetweenSyncs)
+ return false;
+ if (layers_[1].last_qp - layers_[0].last_qp < kMaxQpDeltaForSync)
+ return true;
+ return false;
}
-void ScreenshareLayers::CalculateFramerate(uint32_t timestamp) {
- timestamp_list_.push_front(timestamp);
- // Remove timestamps older than 1 second from the list.
- uint32_t timestamp_diff = timestamp - timestamp_list_.back();
- while (timestamp_diff > kOneSecond90Khz) {
- timestamp_list_.pop_back();
- timestamp_diff = timestamp - timestamp_list_.back();
+bool ScreenshareLayers::UpdateConfiguration(vpx_codec_enc_cfg_t* cfg) {
+ if (max_qp_ == -1)
+ return false;
+
+ unsigned int adjusted_max_qp;
+ if (layers_[active_layer_].state == TemporalLayer::State::kQualityBoost &&
stefan-webrtc 2015/06/18 09:39:02 Comment to describe what you are doing with this i
sprang_webrtc 2015/06/18 13:05:02 Done.
+ layers_[active_layer_].enhanced_max_qp != -1) {
+ adjusted_max_qp = layers_[active_layer_].enhanced_max_qp;
+ layers_[active_layer_].state = TemporalLayer::State::kNormal;
+ } else {
+ if (max_qp_ == -1)
+ return false;
+ adjusted_max_qp = max_qp_;
}
- // If we have encoded frames within the last second, that number of frames
- // is a reasonable first estimate of the framerate.
- framerate_ = timestamp_list_.size();
- if (timestamp_diff > 0) {
- // Estimate the framerate by dividing the number of timestamp diffs with
- // the sum of the timestamp diffs (with rounding).
- framerate_ = (kOneSecond90Khz * (timestamp_list_.size() - 1) +
- timestamp_diff / 2) / timestamp_diff;
+
+ if (adjusted_max_qp == cfg->rc_max_quantizer)
+ return false;
+
+ cfg->rc_max_quantizer = adjusted_max_qp;
+ return true;
+}
+
+void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) {
+ uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8;
+ if (debt_reduction_bytes >= debt_bytes_) {
+ debt_bytes_ = 0;
+ } else {
+ debt_bytes_ -= debt_reduction_bytes;
}
}

Powered by Google App Engine
This is Rietveld 408576698