Make keyframe generation/request intervals configurable through field trials.
Bug: webrtc:10427 Change-Id: I5e7182fc8932943adc3e5f147be51b0b5df93172 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127882 Reviewed-by: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Jonas Oreland <jonaso@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Rasmus Brandt <brandtr@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27233}
This commit is contained in:
parent
fb04dd253e
commit
3dde450f02
@ -132,6 +132,19 @@ rtc_static_library("rate_control_settings") {
|
||||
]
|
||||
}
|
||||
|
||||
rtc_static_library("keyframe_interval_settings_experiment") {
|
||||
sources = [
|
||||
"keyframe_interval_settings.cc",
|
||||
"keyframe_interval_settings.h",
|
||||
]
|
||||
deps = [
|
||||
":field_trial_parser",
|
||||
"../../api/transport:field_trial_based_config",
|
||||
"../../api/transport:webrtc_key_value_config",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_source_set("experiments_unittests") {
|
||||
testonly = true
|
||||
@ -140,6 +153,7 @@ if (rtc_include_tests) {
|
||||
"cpu_speed_experiment_unittest.cc",
|
||||
"field_trial_parser_unittest.cc",
|
||||
"field_trial_units_unittest.cc",
|
||||
"keyframe_interval_settings_unittest.cc",
|
||||
"normalize_simulcast_size_experiment_unittest.cc",
|
||||
"quality_scaling_experiment_unittest.cc",
|
||||
"rate_control_settings_unittest.cc",
|
||||
@ -148,6 +162,7 @@ if (rtc_include_tests) {
|
||||
deps = [
|
||||
":cpu_speed_experiment",
|
||||
":field_trial_parser",
|
||||
":keyframe_interval_settings_experiment",
|
||||
":normalize_simulcast_size_experiment",
|
||||
":quality_scaling_experiment",
|
||||
":rate_control_settings",
|
||||
|
||||
@ -4,6 +4,7 @@ per-file congestion_controller_experiment*=srte@webrtc.org
|
||||
per-file cpu_speed_experiment*=asapersson@webrtc.org
|
||||
per-file field_trial*=srte@webrtc.org
|
||||
per-file jitter_upper_bound_experiment*=sprang@webrtc.org
|
||||
per-file keyframe_interval_settings*=brandtr@webrtc.org
|
||||
per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org
|
||||
per-file quality_scaling_experiment*=asapersson@webrtc.org
|
||||
per-file rtt_mult_experiment*=mhoro@webrtc.org
|
||||
|
||||
51
rtc_base/experiments/keyframe_interval_settings.cc
Normal file
51
rtc_base/experiments/keyframe_interval_settings.cc
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kFieldTrialName[] = "WebRTC-KeyframeInterval";
|
||||
|
||||
} // namespace
|
||||
|
||||
KeyframeIntervalSettings::KeyframeIntervalSettings(
|
||||
const WebRtcKeyValueConfig* const key_value_config)
|
||||
: min_keyframe_send_interval_ms_("min_keyframe_send_interval_ms"),
|
||||
max_wait_for_keyframe_ms_("max_wait_for_keyframe_ms"),
|
||||
max_wait_for_frame_ms_("max_wait_for_frame_ms") {
|
||||
ParseFieldTrial({&min_keyframe_send_interval_ms_, &max_wait_for_keyframe_ms_,
|
||||
&max_wait_for_frame_ms_},
|
||||
key_value_config->Lookup(kFieldTrialName));
|
||||
}
|
||||
|
||||
KeyframeIntervalSettings KeyframeIntervalSettings::ParseFromFieldTrials() {
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
return KeyframeIntervalSettings(&field_trial_config);
|
||||
}
|
||||
|
||||
absl::optional<int> KeyframeIntervalSettings::MinKeyframeSendIntervalMs()
|
||||
const {
|
||||
return min_keyframe_send_interval_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> KeyframeIntervalSettings::MaxWaitForKeyframeMs() const {
|
||||
return max_wait_for_keyframe_ms_.GetOptional();
|
||||
}
|
||||
|
||||
absl::optional<int> KeyframeIntervalSettings::MaxWaitForFrameMs() const {
|
||||
return max_wait_for_frame_ms_.GetOptional();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
48
rtc_base/experiments/keyframe_interval_settings.h
Normal file
48
rtc_base/experiments/keyframe_interval_settings.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
#define RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class KeyframeIntervalSettings final {
|
||||
public:
|
||||
static KeyframeIntervalSettings ParseFromFieldTrials();
|
||||
|
||||
// Sender side.
|
||||
// The encoded keyframe send rate is <= 1/MinKeyframeSendIntervalMs().
|
||||
absl::optional<int> MinKeyframeSendIntervalMs() const;
|
||||
|
||||
// Receiver side.
|
||||
// The keyframe request send rate is
|
||||
// - when we have not received a key frame at all:
|
||||
// <= 1/MaxWaitForKeyframeMs()
|
||||
// - when we have not received a frame recently:
|
||||
// <= 1/MaxWaitForFrameMs()
|
||||
absl::optional<int> MaxWaitForKeyframeMs() const;
|
||||
absl::optional<int> MaxWaitForFrameMs() const;
|
||||
|
||||
private:
|
||||
explicit KeyframeIntervalSettings(
|
||||
const WebRtcKeyValueConfig* key_value_config);
|
||||
|
||||
FieldTrialOptional<int> min_keyframe_send_interval_ms_;
|
||||
FieldTrialOptional<int> max_wait_for_keyframe_ms_;
|
||||
FieldTrialOptional<int> max_wait_for_frame_ms_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_
|
||||
86
rtc_base/experiments/keyframe_interval_settings_unittest.cc
Normal file
86
rtc_base/experiments/keyframe_interval_settings_unittest.cc
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
#include "test/field_trial.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
TEST(KeyframeIntervalSettingsTest, ParsesMinKeyframeSendIntervalMs) {
|
||||
EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MinKeyframeSendIntervalMs());
|
||||
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-KeyframeInterval/min_keyframe_send_interval_ms:100/");
|
||||
EXPECT_EQ(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MinKeyframeSendIntervalMs(),
|
||||
100);
|
||||
}
|
||||
|
||||
TEST(KeyframeIntervalSettingsTest, ParsesMaxWaitForKeyframeMs) {
|
||||
EXPECT_FALSE(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForKeyframeMs());
|
||||
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-KeyframeInterval/max_wait_for_keyframe_ms:100/");
|
||||
EXPECT_EQ(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForKeyframeMs(),
|
||||
100);
|
||||
}
|
||||
|
||||
TEST(KeyframeIntervalSettingsTest, ParsesMaxWaitForFrameMs) {
|
||||
EXPECT_FALSE(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForFrameMs());
|
||||
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-KeyframeInterval/max_wait_for_frame_ms:100/");
|
||||
EXPECT_EQ(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForFrameMs(),
|
||||
100);
|
||||
}
|
||||
|
||||
TEST(KeyframeIntervalSettingsTest, ParsesAllValues) {
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-KeyframeInterval/"
|
||||
"min_keyframe_send_interval_ms:100,"
|
||||
"max_wait_for_keyframe_ms:101,"
|
||||
"max_wait_for_frame_ms:102/");
|
||||
EXPECT_EQ(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MinKeyframeSendIntervalMs(),
|
||||
100);
|
||||
EXPECT_EQ(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForKeyframeMs(),
|
||||
101);
|
||||
EXPECT_EQ(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForFrameMs(),
|
||||
102);
|
||||
}
|
||||
|
||||
TEST(KeyframeIntervalSettingsTest, DoesNotParseAllValuesWhenIncorrectlySet) {
|
||||
EXPECT_FALSE(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForFrameMs());
|
||||
|
||||
test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-KeyframeInterval/"
|
||||
"min_keyframe_send_interval_ms:a,"
|
||||
"max_wait_for_keyframe_ms:b,"
|
||||
"max_wait_for_frame_ms:c/");
|
||||
EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MinKeyframeSendIntervalMs());
|
||||
EXPECT_FALSE(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForKeyframeMs());
|
||||
EXPECT_FALSE(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials().MaxWaitForFrameMs());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc
|
||||
@ -99,6 +99,7 @@ rtc_static_library("video") {
|
||||
"../rtc_base:stringutils",
|
||||
"../rtc_base:weak_ptr",
|
||||
"../rtc_base/experiments:alr_experiment",
|
||||
"../rtc_base/experiments:keyframe_interval_settings_experiment",
|
||||
"../rtc_base/experiments:quality_scaling_experiment",
|
||||
"../rtc_base/experiments:rate_control_settings",
|
||||
"../rtc_base/system:fallthrough",
|
||||
|
||||
@ -10,12 +10,16 @@
|
||||
|
||||
#include "video/encoder_key_frame_callback.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
static const int kMinKeyFrameRequestIntervalMs = 300;
|
||||
#include "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
constexpr int kMinKeyframeSendIntervalMs = 300;
|
||||
} // namespace
|
||||
|
||||
EncoderKeyFrameCallback::EncoderKeyFrameCallback(
|
||||
Clock* clock,
|
||||
const std::vector<uint32_t>& ssrcs,
|
||||
@ -23,7 +27,11 @@ EncoderKeyFrameCallback::EncoderKeyFrameCallback(
|
||||
: clock_(clock),
|
||||
ssrcs_(ssrcs),
|
||||
video_stream_encoder_(encoder),
|
||||
time_last_intra_request_ms_(-1) {
|
||||
time_last_intra_request_ms_(-1),
|
||||
min_keyframe_send_interval_ms_(
|
||||
KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MinKeyframeSendIntervalMs()
|
||||
.value_or(kMinKeyframeSendIntervalMs)) {
|
||||
RTC_DCHECK(!ssrcs.empty());
|
||||
}
|
||||
|
||||
@ -41,7 +49,7 @@ void EncoderKeyFrameCallback::OnReceivedIntraFrameRequest(uint32_t ssrc) {
|
||||
{
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
rtc::CritScope lock(&crit_);
|
||||
if (time_last_intra_request_ms_ + kMinKeyFrameRequestIntervalMs > now_ms) {
|
||||
if (time_last_intra_request_ms_ + min_keyframe_send_interval_ms_ > now_ms) {
|
||||
return;
|
||||
}
|
||||
time_last_intra_request_ms_ = now_ms;
|
||||
|
||||
@ -46,6 +46,8 @@ class EncoderKeyFrameCallback : public RtcpIntraFrameObserver,
|
||||
|
||||
rtc::CriticalSection crit_;
|
||||
int64_t time_last_intra_request_ms_ RTC_GUARDED_BY(crit_);
|
||||
|
||||
const int min_keyframe_send_interval_ms_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
#include "modules/video_coding/timing.h"
|
||||
#include "modules/video_coding/utility/vp8_header_parser.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/experiments/keyframe_interval_settings.h"
|
||||
#include "rtc_base/location.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_file.h"
|
||||
@ -58,6 +59,9 @@ namespace {
|
||||
constexpr int kMinBaseMinimumDelayMs = 0;
|
||||
constexpr int kMaxBaseMinimumDelayMs = 10000;
|
||||
|
||||
constexpr int kMaxWaitForKeyFrameMs = 200;
|
||||
constexpr int kMaxWaitForFrameMs = 3000;
|
||||
|
||||
VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
|
||||
VideoCodec codec;
|
||||
memset(&codec, 0, sizeof(codec));
|
||||
@ -205,7 +209,13 @@ VideoReceiveStream::VideoReceiveStream(
|
||||
this, // KeyFrameRequestSender
|
||||
this, // OnCompleteFrameCallback
|
||||
config_.frame_decryptor),
|
||||
rtp_stream_sync_(this) {
|
||||
rtp_stream_sync_(this),
|
||||
max_wait_for_keyframe_ms_(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MaxWaitForKeyframeMs()
|
||||
.value_or(kMaxWaitForKeyFrameMs)),
|
||||
max_wait_for_frame_ms_(KeyframeIntervalSettings::ParseFromFieldTrials()
|
||||
.MaxWaitForFrameMs()
|
||||
.value_or(kMaxWaitForFrameMs)) {
|
||||
RTC_LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
|
||||
|
||||
RTC_DCHECK(config_.renderer);
|
||||
@ -565,10 +575,9 @@ void VideoReceiveStream::DecodeThreadFunction(void* ptr) {
|
||||
|
||||
bool VideoReceiveStream::Decode() {
|
||||
TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
|
||||
static const int kMaxWaitForFrameMs = 3000;
|
||||
static const int kMaxWaitForKeyFrameMs = 200;
|
||||
|
||||
int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
|
||||
const int wait_ms =
|
||||
keyframe_required_ ? max_wait_for_keyframe_ms_ : max_wait_for_frame_ms_;
|
||||
std::unique_ptr<video_coding::EncodedFrame> frame;
|
||||
// TODO(philipel): Call NextFrame with |keyframe_required| argument when
|
||||
// downstream project has been fixed.
|
||||
@ -602,7 +611,8 @@ bool VideoReceiveStream::Decode() {
|
||||
if (decode_result == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME)
|
||||
RequestKeyFrame();
|
||||
} else if (!frame_decoded_ || !keyframe_required_ ||
|
||||
(last_keyframe_request_ms_ + kMaxWaitForKeyFrameMs < now_ms)) {
|
||||
(last_keyframe_request_ms_ + max_wait_for_keyframe_ms_ <
|
||||
now_ms)) {
|
||||
keyframe_required_ = true;
|
||||
// TODO(philipel): Remove this keyframe request when downstream project
|
||||
// has been fixed.
|
||||
@ -627,7 +637,7 @@ bool VideoReceiveStream::Decode() {
|
||||
// we assume a keyframe is currently being received.
|
||||
bool receiving_keyframe =
|
||||
last_keyframe_packet_ms &&
|
||||
now_ms - *last_keyframe_packet_ms < kMaxWaitForKeyFrameMs;
|
||||
now_ms - *last_keyframe_packet_ms < max_wait_for_keyframe_ms_;
|
||||
|
||||
if (stream_is_active && !receiving_keyframe &&
|
||||
(!config_.crypto_options.sframe.require_frame_encryption ||
|
||||
|
||||
@ -184,6 +184,10 @@ class VideoReceiveStream : public webrtc::VideoReceiveStream,
|
||||
int64_t last_keyframe_request_ms_ = 0;
|
||||
int64_t last_complete_frame_time_ms_ = 0;
|
||||
|
||||
// Keyframe request intervals are configurable through field trials.
|
||||
const int max_wait_for_keyframe_ms_;
|
||||
const int max_wait_for_frame_ms_;
|
||||
|
||||
rtc::CriticalSection playout_delay_lock_;
|
||||
|
||||
// All of them tries to change current min_playout_delay on |timing_| but
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user