Don't trigger key frame when encoder is not reset during reconfigure
Currently, key frames are scheduled even when the encoder is not reset during reconfigeration. This means whenever new parameters like max bitrate or min bitrate are updated through SetRtpParameters(), the triggered encoder reconfigeration will always schedule key frames even they are not necessary. Since parameters' changes like bitrate doesn't require encoder instance reset. This causes flood of key frames in our app since we do regularly max bitrate update according to server control message. Bug: None Change-Id: I15d953b24c30e6026c0e97b30f44495d845f293f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/185380 Commit-Queue: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32245}
This commit is contained in:
@ -115,21 +115,39 @@ bool RequiresEncoderReset(const VideoCodec& prev_send_codec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
|
for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
|
||||||
if (new_send_codec.simulcastStream[i].width !=
|
if (!new_send_codec.simulcastStream[i].active) {
|
||||||
|
// No need to reset when stream is inactive.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prev_send_codec.simulcastStream[i].active ||
|
||||||
|
new_send_codec.simulcastStream[i].width !=
|
||||||
prev_send_codec.simulcastStream[i].width ||
|
prev_send_codec.simulcastStream[i].width ||
|
||||||
new_send_codec.simulcastStream[i].height !=
|
new_send_codec.simulcastStream[i].height !=
|
||||||
prev_send_codec.simulcastStream[i].height ||
|
prev_send_codec.simulcastStream[i].height ||
|
||||||
new_send_codec.simulcastStream[i].maxFramerate !=
|
|
||||||
prev_send_codec.simulcastStream[i].maxFramerate ||
|
|
||||||
new_send_codec.simulcastStream[i].numberOfTemporalLayers !=
|
new_send_codec.simulcastStream[i].numberOfTemporalLayers !=
|
||||||
prev_send_codec.simulcastStream[i].numberOfTemporalLayers ||
|
prev_send_codec.simulcastStream[i].numberOfTemporalLayers ||
|
||||||
new_send_codec.simulcastStream[i].qpMax !=
|
new_send_codec.simulcastStream[i].qpMax !=
|
||||||
prev_send_codec.simulcastStream[i].qpMax ||
|
prev_send_codec.simulcastStream[i].qpMax) {
|
||||||
new_send_codec.simulcastStream[i].active !=
|
|
||||||
prev_send_codec.simulcastStream[i].active) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_send_codec.codecType == kVideoCodecVP9) {
|
||||||
|
size_t num_spatial_layers = new_send_codec.VP9().numberOfSpatialLayers;
|
||||||
|
for (unsigned char i = 0; i < num_spatial_layers; ++i) {
|
||||||
|
if (new_send_codec.spatialLayers[i].width !=
|
||||||
|
prev_send_codec.spatialLayers[i].width ||
|
||||||
|
new_send_codec.spatialLayers[i].height !=
|
||||||
|
prev_send_codec.spatialLayers[i].height ||
|
||||||
|
new_send_codec.spatialLayers[i].numberOfTemporalLayers !=
|
||||||
|
prev_send_codec.spatialLayers[i].numberOfTemporalLayers ||
|
||||||
|
new_send_codec.spatialLayers[i].qpMax !=
|
||||||
|
prev_send_codec.spatialLayers[i].qpMax) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +774,7 @@ void VideoStreamEncoder::ReconfigureEncoder() {
|
|||||||
// start bitrate or max framerate has changed.
|
// start bitrate or max framerate has changed.
|
||||||
if (!encoder_reset_required) {
|
if (!encoder_reset_required) {
|
||||||
encoder_reset_required = RequiresEncoderReset(
|
encoder_reset_required = RequiresEncoderReset(
|
||||||
codec, send_codec_, was_encode_called_since_last_initialization_);
|
send_codec_, codec, was_encode_called_since_last_initialization_);
|
||||||
}
|
}
|
||||||
send_codec_ = codec;
|
send_codec_ = codec;
|
||||||
|
|
||||||
@ -787,6 +805,10 @@ void VideoStreamEncoder::ReconfigureEncoder() {
|
|||||||
encoder_->RegisterEncodeCompleteCallback(this);
|
encoder_->RegisterEncodeCompleteCallback(this);
|
||||||
frame_encode_metadata_writer_.OnEncoderInit(send_codec_,
|
frame_encode_metadata_writer_.OnEncoderInit(send_codec_,
|
||||||
HasInternalSource());
|
HasInternalSource());
|
||||||
|
next_frame_types_.clear();
|
||||||
|
next_frame_types_.resize(
|
||||||
|
std::max(static_cast<int>(codec.numberOfSimulcastStreams), 1),
|
||||||
|
VideoFrameType::kVideoFrameKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_encode_metadata_writer_.Reset();
|
frame_encode_metadata_writer_.Reset();
|
||||||
@ -798,10 +820,6 @@ void VideoStreamEncoder::ReconfigureEncoder() {
|
|||||||
OnEncoderSettingsChanged();
|
OnEncoderSettingsChanged();
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
next_frame_types_.clear();
|
|
||||||
next_frame_types_.resize(
|
|
||||||
std::max(static_cast<int>(codec.numberOfSimulcastStreams), 1),
|
|
||||||
VideoFrameType::kVideoFrameKey);
|
|
||||||
RTC_LOG(LS_VERBOSE) << " max bitrate " << codec.maxBitrate
|
RTC_LOG(LS_VERBOSE) << " max bitrate " << codec.maxBitrate
|
||||||
<< " start bitrate " << codec.startBitrate
|
<< " start bitrate " << codec.startBitrate
|
||||||
<< " max frame rate " << codec.maxFramerate
|
<< " max frame rate " << codec.maxFramerate
|
||||||
|
@ -6149,4 +6149,94 @@ TEST_F(VideoStreamEncoderTest, ConfiguresVp9SvcAtOddResolutions) {
|
|||||||
video_stream_encoder_->Stop();
|
video_stream_encoder_->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoStreamEncoderTest, EncoderResetAccordingToParameterChange) {
|
||||||
|
const float downscale_factors[] = {4.0, 2.0, 1.0};
|
||||||
|
const int number_layers =
|
||||||
|
sizeof(downscale_factors) / sizeof(downscale_factors[0]);
|
||||||
|
VideoEncoderConfig config;
|
||||||
|
test::FillEncoderConfiguration(kVideoCodecVP8, number_layers, &config);
|
||||||
|
for (int i = 0; i < number_layers; ++i) {
|
||||||
|
config.simulcast_layers[i].scale_resolution_down_by = downscale_factors[i];
|
||||||
|
config.simulcast_layers[i].active = true;
|
||||||
|
}
|
||||||
|
config.video_stream_factory =
|
||||||
|
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
|
||||||
|
"VP8", /*max qp*/ 56, /*screencast*/ false,
|
||||||
|
/*screenshare enabled*/ false);
|
||||||
|
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||||
|
DataRate::BitsPerSec(kSimulcastTargetBitrateBps),
|
||||||
|
DataRate::BitsPerSec(kSimulcastTargetBitrateBps),
|
||||||
|
DataRate::BitsPerSec(kSimulcastTargetBitrateBps), 0, 0, 0);
|
||||||
|
|
||||||
|
// First initialization.
|
||||||
|
// Encoder should be initialized. Next frame should be key frame.
|
||||||
|
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
|
||||||
|
sink_.SetNumExpectedLayers(number_layers);
|
||||||
|
int64_t timestamp_ms = kFrameIntervalMs;
|
||||||
|
video_source_.IncomingCapturedFrame(CreateFrame(timestamp_ms, 1280, 720));
|
||||||
|
WaitForEncodedFrame(timestamp_ms);
|
||||||
|
EXPECT_EQ(1, fake_encoder_.GetNumEncoderInitializations());
|
||||||
|
EXPECT_THAT(fake_encoder_.LastFrameTypes(),
|
||||||
|
::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey}));
|
||||||
|
|
||||||
|
// Disable top layer.
|
||||||
|
// Encoder shouldn't be re-initialized. Next frame should be delta frame.
|
||||||
|
config.simulcast_layers[number_layers - 1].active = false;
|
||||||
|
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
|
||||||
|
sink_.SetNumExpectedLayers(number_layers - 1);
|
||||||
|
timestamp_ms += kFrameIntervalMs;
|
||||||
|
video_source_.IncomingCapturedFrame(CreateFrame(timestamp_ms, 1280, 720));
|
||||||
|
WaitForEncodedFrame(timestamp_ms);
|
||||||
|
EXPECT_EQ(1, fake_encoder_.GetNumEncoderInitializations());
|
||||||
|
EXPECT_THAT(fake_encoder_.LastFrameTypes(),
|
||||||
|
::testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
|
||||||
|
VideoFrameType::kVideoFrameDelta,
|
||||||
|
VideoFrameType::kVideoFrameDelta}));
|
||||||
|
|
||||||
|
// Re-enable top layer.
|
||||||
|
// Encoder should be re-initialized. Next frame should be key frame.
|
||||||
|
config.simulcast_layers[number_layers - 1].active = true;
|
||||||
|
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
|
||||||
|
sink_.SetNumExpectedLayers(number_layers);
|
||||||
|
timestamp_ms += kFrameIntervalMs;
|
||||||
|
video_source_.IncomingCapturedFrame(CreateFrame(timestamp_ms, 1280, 720));
|
||||||
|
WaitForEncodedFrame(timestamp_ms);
|
||||||
|
EXPECT_EQ(2, fake_encoder_.GetNumEncoderInitializations());
|
||||||
|
EXPECT_THAT(fake_encoder_.LastFrameTypes(),
|
||||||
|
::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey}));
|
||||||
|
|
||||||
|
// Top layer max rate change.
|
||||||
|
// Encoder shouldn't be re-initialized. Next frame should be delta frame.
|
||||||
|
config.simulcast_layers[number_layers - 1].max_bitrate_bps -= 100;
|
||||||
|
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
|
||||||
|
sink_.SetNumExpectedLayers(number_layers);
|
||||||
|
timestamp_ms += kFrameIntervalMs;
|
||||||
|
video_source_.IncomingCapturedFrame(CreateFrame(timestamp_ms, 1280, 720));
|
||||||
|
WaitForEncodedFrame(timestamp_ms);
|
||||||
|
EXPECT_EQ(2, fake_encoder_.GetNumEncoderInitializations());
|
||||||
|
EXPECT_THAT(fake_encoder_.LastFrameTypes(),
|
||||||
|
::testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
|
||||||
|
VideoFrameType::kVideoFrameDelta,
|
||||||
|
VideoFrameType::kVideoFrameDelta}));
|
||||||
|
|
||||||
|
// Top layer resolution change.
|
||||||
|
// Encoder should be re-initialized. Next frame should be key frame.
|
||||||
|
config.simulcast_layers[number_layers - 1].scale_resolution_down_by += 0.1;
|
||||||
|
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
|
||||||
|
sink_.SetNumExpectedLayers(number_layers);
|
||||||
|
timestamp_ms += kFrameIntervalMs;
|
||||||
|
video_source_.IncomingCapturedFrame(CreateFrame(timestamp_ms, 1280, 720));
|
||||||
|
WaitForEncodedFrame(timestamp_ms);
|
||||||
|
EXPECT_EQ(3, fake_encoder_.GetNumEncoderInitializations());
|
||||||
|
EXPECT_THAT(fake_encoder_.LastFrameTypes(),
|
||||||
|
::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey,
|
||||||
|
VideoFrameType::kVideoFrameKey}));
|
||||||
|
video_stream_encoder_->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
Reference in New Issue
Block a user