Add overshoot of target bitrate for screenshare with temporal layers.
Set the codec target bitrate higher than TL0 but lower than TL1, making sure frame rate is not too low (but still lower than TL1) and that overshooting for complex scenes don't overly exceed TL1 bitrates. BUG=4083 R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/34479004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7929 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
45a272ab22
commit
70f74f3f7b
@ -14,11 +14,15 @@
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
|
||||
#include "webrtc/system_wrappers/interface/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum { kOneSecond90Khz = 90000 };
|
||||
|
||||
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,
|
||||
@ -97,6 +101,20 @@ bool ScreenshareLayers::ConfigureBitrates(int bitrate_kbit,
|
||||
}
|
||||
tl0_frame_dropper_->SetRates(bitrate_kbit, framerate_);
|
||||
tl1_frame_dropper_->SetRates(max_bitrate_kbit, framerate_);
|
||||
|
||||
if (cfg != NULL && TargetBitrateExperimentEnabled()) {
|
||||
// Calculate a codec target bitrate. This may be higher than TL0, gaining
|
||||
// quality at the expense of frame rate at TL0. Constraints:
|
||||
// - TL0 frame rate should not be less than framerate / kMaxTL0FpsReduction.
|
||||
// - Target rate * kAcceptableTargetOvershoot should not exceed TL1 rate.
|
||||
double target_bitrate =
|
||||
std::min(bitrate_kbit * kMaxTL0FpsReduction,
|
||||
max_bitrate_kbit / kAcceptableTargetOvershoot);
|
||||
cfg->rc_target_bitrate =
|
||||
std::max(static_cast<unsigned int>(bitrate_kbit),
|
||||
static_cast<unsigned int>(target_bitrate + 0.5));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,4 +174,11 @@ void ScreenshareLayers::CalculateFramerate(uint32_t timestamp) {
|
||||
timestamp_diff / 2) / timestamp_diff;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScreenshareLayers::TargetBitrateExperimentEnabled() {
|
||||
std::string group =
|
||||
field_trial::FindFullName("WebRTC-ScreencastTargetBitrateOvershoot");
|
||||
return group == "Enabled";
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -24,6 +24,9 @@ struct CodecSpecificInfoVP8;
|
||||
|
||||
class ScreenshareLayers : public TemporalLayers {
|
||||
public:
|
||||
static const double kMaxTL0FpsReduction;
|
||||
static const double kAcceptableTargetOvershoot;
|
||||
|
||||
ScreenshareLayers(int num_temporal_layers,
|
||||
uint8_t initial_tl0_pic_idx,
|
||||
FrameDropper* tl0_frame_dropper,
|
||||
@ -47,6 +50,9 @@ class ScreenshareLayers : public TemporalLayers {
|
||||
|
||||
virtual int CurrentLayerId() const;
|
||||
|
||||
protected:
|
||||
virtual bool TargetBitrateExperimentEnabled();
|
||||
|
||||
private:
|
||||
void CalculateFramerate(uint32_t timestamp);
|
||||
bool TimeToSync(uint32_t timestamp) const;
|
||||
|
@ -33,6 +33,22 @@ const int kFlagsTL1 = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
|
||||
const int kFlagsTL1Sync = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF |
|
||||
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
|
||||
class ScreenshareLayersFT : public ScreenshareLayers {
|
||||
public:
|
||||
ScreenshareLayersFT(int num_temporal_layers,
|
||||
uint8_t initial_tl0_pic_idx,
|
||||
FrameDropper* tl0_frame_dropper,
|
||||
FrameDropper* tl1_frame_dropper)
|
||||
: ScreenshareLayers(num_temporal_layers,
|
||||
initial_tl0_pic_idx,
|
||||
tl0_frame_dropper,
|
||||
tl1_frame_dropper) {}
|
||||
virtual ~ScreenshareLayersFT() {}
|
||||
|
||||
protected:
|
||||
virtual bool TargetBitrateExperimentEnabled() OVERRIDE { return true; }
|
||||
};
|
||||
|
||||
class ScreenshareLayerTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetEncodeExpectations(bool drop_tl0, bool drop_tl1, int framerate) {
|
||||
@ -77,12 +93,12 @@ class ScreenshareLayerTest : public ::testing::Test {
|
||||
|
||||
NiceMock<MockFrameDropper> tl0_frame_dropper_;
|
||||
NiceMock<MockFrameDropper> tl1_frame_dropper_;
|
||||
scoped_ptr<ScreenshareLayers> layers_;
|
||||
scoped_ptr<ScreenshareLayersFT> layers_;
|
||||
};
|
||||
|
||||
TEST_F(ScreenshareLayerTest, 1Layer) {
|
||||
layers_.reset(new ScreenshareLayers(1, 0, &tl0_frame_dropper_,
|
||||
&tl1_frame_dropper_));
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(1, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
EXPECT_TRUE(layers_->ConfigureBitrates(100, 1000, 5, NULL));
|
||||
int flags = 0;
|
||||
uint32_t timestamp = 0;
|
||||
@ -116,8 +132,8 @@ TEST_F(ScreenshareLayerTest, 1Layer) {
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, 2Layer) {
|
||||
layers_.reset(new ScreenshareLayers(2, 0, &tl0_frame_dropper_,
|
||||
&tl1_frame_dropper_));
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
EXPECT_TRUE(layers_->ConfigureBitrates(100, 1000, 5, NULL));
|
||||
int flags = 0;
|
||||
uint32_t timestamp = 0;
|
||||
@ -164,8 +180,8 @@ TEST_F(ScreenshareLayerTest, 2Layer) {
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, 2LayersPeriodicSync) {
|
||||
layers_.reset(new ScreenshareLayers(2, 0, &tl0_frame_dropper_,
|
||||
&tl1_frame_dropper_));
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
EXPECT_TRUE(layers_->ConfigureBitrates(100, 1000, 5, NULL));
|
||||
int flags = 0;
|
||||
uint32_t timestamp = 0;
|
||||
@ -188,8 +204,8 @@ TEST_F(ScreenshareLayerTest, 2LayersPeriodicSync) {
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, 2LayersToggling) {
|
||||
layers_.reset(new ScreenshareLayers(2, 0, &tl0_frame_dropper_,
|
||||
&tl1_frame_dropper_));
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
EXPECT_TRUE(layers_->ConfigureBitrates(100, 1000, 5, NULL));
|
||||
int flags = 0;
|
||||
uint32_t timestamp = 0;
|
||||
@ -213,8 +229,8 @@ TEST_F(ScreenshareLayerTest, 2LayersToggling) {
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, 2LayersBothDrops) {
|
||||
layers_.reset(new ScreenshareLayers(2, 0, &tl0_frame_dropper_,
|
||||
&tl1_frame_dropper_));
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
EXPECT_TRUE(layers_->ConfigureBitrates(100, 1000, 5, NULL));
|
||||
int flags = 0;
|
||||
uint32_t timestamp = 0;
|
||||
@ -241,4 +257,37 @@ TEST_F(ScreenshareLayerTest, 2LayersBothDrops) {
|
||||
flags = layers_->EncodeFlags(timestamp);
|
||||
EXPECT_EQ(-1, flags);
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, TargetBitrateCappedByTL0) {
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
layers_->ConfigureBitrates(100, 1000, 5, &cfg);
|
||||
|
||||
EXPECT_EQ(static_cast<unsigned int>(
|
||||
ScreenshareLayers::kMaxTL0FpsReduction * 100 + 0.5),
|
||||
cfg.rc_target_bitrate);
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, TargetBitrateCappedByTL1) {
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
layers_->ConfigureBitrates(100, 450, 5, &cfg);
|
||||
|
||||
EXPECT_EQ(static_cast<unsigned int>(
|
||||
450 / ScreenshareLayers::kAcceptableTargetOvershoot),
|
||||
cfg.rc_target_bitrate);
|
||||
}
|
||||
|
||||
TEST_F(ScreenshareLayerTest, TargetBitrateBelowTL0) {
|
||||
layers_.reset(
|
||||
new ScreenshareLayersFT(2, 0, &tl0_frame_dropper_, &tl1_frame_dropper_));
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
layers_->ConfigureBitrates(100, 100, 5, &cfg);
|
||||
|
||||
EXPECT_EQ(100U, cfg.rc_target_bitrate);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
Loading…
x
Reference in New Issue
Block a user