Don't drop keyframes even if TemporalLayers says so.

This CL is a minimum effort/low risk fix.
Later CLs take a more thorough approach.

Bug: webrtc:9634
Change-Id: I728a061a4e71b38a559ee438646de83cd2cb3517
Reviewed-on: https://webrtc-review.googlesource.com/94760
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24326}
This commit is contained in:
Erik Språng
2018-08-17 13:21:48 +02:00
committed by Commit Bot
parent adc4879909
commit 506c569443
4 changed files with 61 additions and 4 deletions

View File

@ -27,6 +27,7 @@
namespace webrtc {
namespace {
const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost";
const char kVp8DontDropKeyframeFieldTrial[] = "WebRTC-Vp8DontDropKeyFrames";
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
@ -152,6 +153,8 @@ vpx_enc_frame_flags_t LibvpxVp8Encoder::EncodeFlags(
LibvpxVp8Encoder::LibvpxVp8Encoder()
: use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)),
prevent_kf_drop_(
!webrtc::field_trial::IsDisabled(kVp8DontDropKeyframeFieldTrial)),
encoded_complete_callback_(nullptr),
inited_(false),
timestamp_(0),
@ -722,6 +725,9 @@ int LibvpxVp8Encoder::Encode(const VideoFrame& frame,
for (size_t i = 0; i < encoders_.size(); ++i) {
tl_configs[i] = temporal_layers_[i]->UpdateLayerConfig(frame.timestamp());
if (tl_configs[i].drop_frame) {
if (send_key_frame && prevent_kf_drop_) {
continue;
}
// Drop this frame.
return WEBRTC_VIDEO_CODEC_OK;
}

View File

@ -85,6 +85,7 @@ class LibvpxVp8Encoder : public VP8Encoder {
uint32_t MaxIntraTarget(uint32_t optimal_buffer_size);
const bool use_gf_boost_;
const bool prevent_kf_drop_;
EncodedImageCallback* encoded_complete_callback_;
VideoCodec codec_;

View File

@ -292,6 +292,7 @@ void ScreenshareLayers::PopulateCodecSpecific(
vp8_info->layerSync = true;
layers_[0].state = TemporalLayer::State::kKeyFrame;
layers_[1].state = TemporalLayer::State::kKeyFrame;
active_layer_ = 1;
}
}
}

View File

@ -55,9 +55,16 @@ class TestVp8Impl : public VideoCodecUnitTest {
void EncodeAndWaitForFrame(const VideoFrame& input_frame,
EncodedImage* encoded_frame,
CodecSpecificInfo* codec_specific_info) {
CodecSpecificInfo* codec_specific_info,
bool keyframe = false) {
std::vector<FrameType> frame_types;
if (keyframe) {
frame_types.emplace_back(FrameType::kVideoFrameKey);
} else {
frame_types.emplace_back(FrameType::kVideoFrameDelta);
}
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(input_frame, nullptr, nullptr));
encoder_->Encode(input_frame, nullptr, &frame_types));
ASSERT_TRUE(WaitForEncodedFrame(encoded_frame, codec_specific_info));
VerifyQpParser(*encoded_frame);
EXPECT_STREQ("libvpx", codec_specific_info->codec_name);
@ -66,10 +73,12 @@ class TestVp8Impl : public VideoCodecUnitTest {
}
void EncodeAndExpectFrameWith(const VideoFrame& input_frame,
uint8_t temporal_idx) {
uint8_t temporal_idx,
bool keyframe = false) {
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
EncodeAndWaitForFrame(input_frame, &encoded_frame, &codec_specific_info);
EncodeAndWaitForFrame(input_frame, &encoded_frame, &codec_specific_info,
keyframe);
EXPECT_EQ(temporal_idx, codec_specific_info.codecSpecific.VP8.temporalIdx);
}
@ -330,4 +339,44 @@ TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) {
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
}
TEST_F(TestVp8Impl, DontDropKeyframes) {
// Set very high resolution to trigger overuse more easily.
const int kScreenWidth = 1920;
const int kScreenHeight = 1080;
codec_settings_.width = kScreenWidth;
codec_settings_.height = kScreenHeight;
// Screensharing has the internal frame dropper off, and instead per frame
// asks ScreenshareLayers to decide if it should be dropped or not.
codec_settings_.VP8()->frameDroppingOn = false;
codec_settings_.mode = VideoCodecMode::kScreensharing;
// ScreenshareLayers triggers on 2 temporal layers and 1000kbps max bitrate.
codec_settings_.VP8()->numberOfTemporalLayers = 2;
codec_settings_.maxBitrate = 1000;
// Reset the frame generator with large number of squares, leading to lots of
// details and high probability of overshoot.
input_frame_generator_ = test::FrameGenerator::CreateSquareGenerator(
codec_settings_.width, codec_settings_.height,
test::FrameGenerator::OutputType::I420,
/* num_squares = */ absl::optional<int>(300));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoBitrateAllocation bitrate_allocation;
// Bitrate only enough for TL0.
bitrate_allocation.SetBitrate(0, 0, 200000);
encoder_->SetRateAllocation(bitrate_allocation, 5);
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
EncodeAndWaitForFrame(*NextInputFrame(), &encoded_frame, &codec_specific_info,
true);
EncodeAndExpectFrameWith(*NextInputFrame(), 0, true);
EncodeAndExpectFrameWith(*NextInputFrame(), 0, true);
EncodeAndExpectFrameWith(*NextInputFrame(), 0, true);
}
} // namespace webrtc