Add initial support for RtpEncodingParameters max_framerate.

Add support to set the framerate to the maximum of |max_framerate|.
Different framerates are currently not supported per stream for video.

Bug: webrtc:9597
Change-Id: Ie326617b66bd97be387f809a7f82b97b8f3ff5fe
Reviewed-on: https://webrtc-review.googlesource.com/92392
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24270}
This commit is contained in:
Åsa Persson
2018-08-10 16:16:43 +02:00
committed by Commit Bot
parent 553b6f68e1
commit ced5cfdb35
14 changed files with 387 additions and 167 deletions

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include <string>
#include "media/base/mediaconstants.h"
#include "media/base/streamparams.h"
#include "media/engine/constants.h"
#include "media/engine/simulcast.h"
@ -189,17 +190,15 @@ std::vector<webrtc::VideoStream> GetSimulcastConfig(
int /*max_bitrate_bps*/,
double bitrate_priority,
int max_qp,
int max_framerate,
int /*max_framerate*/,
bool is_screenshare,
bool temporal_layers_supported) {
if (is_screenshare) {
return GetScreenshareLayers(max_layers, width, height, bitrate_priority,
max_qp, max_framerate,
temporal_layers_supported);
max_qp, temporal_layers_supported);
} else {
return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
max_qp, max_framerate,
temporal_layers_supported);
max_qp, temporal_layers_supported);
}
}
@ -209,7 +208,6 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
int height,
double bitrate_priority,
int max_qp,
int max_framerate,
bool temporal_layers_supported) {
// TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough
// (defined in kSimulcastFormats) we scale down the number of simulcast
@ -270,7 +268,7 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
static_cast<int>(layers[s].target_bitrate_bps * rate_factor);
}
layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height);
layers[s].max_framerate = max_framerate;
layers[s].max_framerate = kDefaultVideoMaxFramerate;
width /= 2;
height /= 2;
@ -294,7 +292,6 @@ std::vector<webrtc::VideoStream> GetScreenshareLayers(
int height,
double bitrate_priority,
int max_qp,
int max_framerate,
bool temporal_layers_supported) {
size_t num_simulcast_layers =
std::min<int>(max_layers, kMaxScreenshareSimulcastLayers);
@ -346,7 +343,7 @@ std::vector<webrtc::VideoStream> GetScreenshareLayers(
layers[1].width = width;
layers[1].height = height;
layers[1].max_qp = max_qp;
layers[1].max_framerate = max_framerate;
layers[1].max_framerate = kDefaultVideoMaxFramerate;
layers[1].num_temporal_layers =
temporal_layers_supported ? DefaultNumberOfTemporalLayers(1) : 0;
layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2;

View File

@ -26,7 +26,7 @@ void BoostMaxSimulcastLayer(int max_bitrate_bps,
std::vector<webrtc::VideoStream>* layers);
// Gets simulcast settings.
// TODO(asapersson): Remove max_bitrate_bps.
// TODO(asapersson): Remove max_bitrate_bps and max_framerate.
std::vector<webrtc::VideoStream> GetSimulcastConfig(
size_t max_layers,
int width,
@ -34,7 +34,7 @@ std::vector<webrtc::VideoStream> GetSimulcastConfig(
int /*max_bitrate_bps*/,
double bitrate_priority,
int max_qp,
int max_framerate,
int /*max_framerate*/,
bool is_screenshare,
bool temporal_layers_supported = true);
@ -45,7 +45,6 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
int height,
double bitrate_priority,
int max_qp,
int max_framerate,
bool temporal_layers_supported = true);
// Gets simulcast config layers for screenshare settings.
@ -55,7 +54,6 @@ std::vector<webrtc::VideoStream> GetScreenshareLayers(
int height,
double bitrate_priority,
int max_qp,
int max_framerate,
bool temporal_layers_supported = true);
} // namespace cricket

View File

@ -10,6 +10,7 @@
#include "media/engine/simulcast.h"
#include "media/base/mediaconstants.h"
#include "media/engine/constants.h"
#include "test/field_trial.h"
#include "test/gtest.h"
@ -94,7 +95,7 @@ TEST(SimulcastTest, GetConfig) {
for (size_t i = 0; i < streams.size(); ++i) {
EXPECT_EQ(size_t{kDefaultTemporalLayers}, streams[i].num_temporal_layers);
EXPECT_EQ(kMaxFps, streams[i].max_framerate);
EXPECT_EQ(cricket::kDefaultVideoMaxFramerate, streams[i].max_framerate);
EXPECT_EQ(kQpMax, streams[i].max_qp);
EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps);
EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps);

View File

@ -250,6 +250,18 @@ std::vector<VideoCodec> AssignPayloadTypesAndDefaultCodecs(
: std::vector<VideoCodec>();
}
int GetMaxFramerate(const webrtc::VideoEncoderConfig& encoder_config,
size_t num_layers) {
int max_fps = -1;
for (size_t i = 0; i < num_layers; ++i) {
int fps = (encoder_config.simulcast_layers[i].max_framerate > 0)
? encoder_config.simulcast_layers[i].max_framerate
: kDefaultVideoMaxFramerate;
max_fps = std::max(fps, max_fps);
}
return max_fps;
}
static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
std::stringstream out;
out << '{';
@ -1802,13 +1814,16 @@ webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
return error;
}
bool new_bitrate = false;
bool new_param = false;
for (size_t i = 0; i < rtp_parameters_.encodings.size(); ++i) {
if ((new_parameters.encodings[i].min_bitrate_bps !=
rtp_parameters_.encodings[i].min_bitrate_bps) ||
(new_parameters.encodings[i].max_bitrate_bps !=
rtp_parameters_.encodings[i].max_bitrate_bps)) {
new_bitrate = true;
rtp_parameters_.encodings[i].max_bitrate_bps) ||
(new_parameters.encodings[i].max_framerate !=
rtp_parameters_.encodings[i].max_framerate)) {
new_param = true;
break;
}
}
@ -1822,8 +1837,8 @@ webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
// entire encoder reconfiguration, it just needs to update the bitrate
// allocator.
bool reconfigure_encoder =
new_bitrate || (new_parameters.encodings[0].bitrate_priority !=
rtp_parameters_.encodings[0].bitrate_priority);
new_param || (new_parameters.encodings[0].bitrate_priority !=
rtp_parameters_.encodings[0].bitrate_priority);
// TODO(bugs.webrtc.org/8807): The active field as well should not require
// a full encoder reconfiguration, but it needs to update both the bitrate
@ -1985,7 +2000,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
// Application-controlled state is held in the encoder_config's
// simulcast_layers. Currently this is used to control which simulcast layers
// are active and for configuring the min/max bitrate.
// are active and for configuring the min/max bitrate and max framerate.
// The encoder_config's simulcast_layers is also used for non-simulcast (when
// there is a single layer).
RTC_DCHECK_GE(rtp_parameters_.encodings.size(),
@ -2003,14 +2018,17 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
encoder_config.simulcast_layers[i].max_bitrate_bps =
*rtp_parameters_.encodings[i].max_bitrate_bps;
}
if (rtp_parameters_.encodings[i].max_framerate) {
encoder_config.simulcast_layers[i].max_framerate =
*rtp_parameters_.encodings[i].max_framerate;
}
}
int max_qp = kDefaultQpMax;
codec.GetParam(kCodecParamMaxQuantization, &max_qp);
encoder_config.video_stream_factory =
new rtc::RefCountedObject<EncoderStreamFactory>(
codec.name, max_qp, kDefaultVideoMaxFramerate, is_screencast,
parameters_.conference_mode);
codec.name, max_qp, is_screencast, parameters_.conference_mode);
return encoder_config;
}
@ -2702,19 +2720,17 @@ WebRtcVideoChannel::MapCodecs(const std::vector<VideoCodec>& codecs) {
return video_codecs;
}
// TODO(bugs.webrtc.org/8785): Consider removing max_qp and max_framerate
// as members of EncoderStreamFactory and instead set these values individually
// for each stream in the VideoEncoderConfig.simulcast_layers.
// TODO(bugs.webrtc.org/8785): Consider removing max_qp as member of
// EncoderStreamFactory and instead set this value individually for each stream
// in the VideoEncoderConfig.simulcast_layers.
EncoderStreamFactory::EncoderStreamFactory(
std::string codec_name,
int max_qp,
int max_framerate,
bool is_screenshare,
bool screenshare_config_explicitly_enabled)
: codec_name_(codec_name),
max_qp_(max_qp),
max_framerate_(max_framerate),
is_screenshare_(is_screenshare),
screenshare_config_explicitly_enabled_(
screenshare_config_explicitly_enabled) {}
@ -2738,12 +2754,18 @@ std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
bool temporal_layers_supported = CodecNamesEq(codec_name_, kVp8CodecName);
layers = GetSimulcastConfig(encoder_config.number_of_streams, width, height,
0 /*not used*/, encoder_config.bitrate_priority,
max_qp_, max_framerate_, is_screenshare_,
max_qp_, 0 /*not_used*/, is_screenshare_,
temporal_layers_supported);
// The maximum |max_framerate| is currently used for video.
int max_framerate = GetMaxFramerate(encoder_config, layers.size());
// Update the active simulcast layers and configured bitrates.
bool is_highest_layer_max_bitrate_configured = false;
for (size_t i = 0; i < layers.size(); ++i) {
layers[i].active = encoder_config.simulcast_layers[i].active;
if (!is_screenshare_) {
// Update simulcast framerates with max configured max framerate.
layers[i].max_framerate = max_framerate;
}
// Update simulcast bitrates with configured min and max bitrate.
if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
layers[i].min_bitrate_bps =
@ -2800,11 +2822,14 @@ std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
if (encoder_config.max_bitrate_bps <= 0)
max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps);
}
int max_framerate = (encoder_config.simulcast_layers[0].max_framerate > 0)
? encoder_config.simulcast_layers[0].max_framerate
: kDefaultVideoMaxFramerate;
webrtc::VideoStream layer;
layer.width = width;
layer.height = height;
layer.max_framerate = max_framerate_;
layer.max_framerate = max_framerate;
// In the case that the application sets a max bitrate that's lower than the
// min bitrate, we adjust it down (see bugs.webrtc.org/9141).

View File

@ -505,7 +505,6 @@ class EncoderStreamFactory
public:
EncoderStreamFactory(std::string codec_name,
int max_qp,
int max_framerate,
bool is_screenshare,
bool screenshare_config_explicitly_enabled);
@ -517,7 +516,6 @@ class EncoderStreamFactory
const std::string codec_name_;
const int max_qp_;
const int max_framerate_;
const bool is_screenshare_;
// Allows a screenshare specific configuration, which enables temporal
// layering and allows simulcast.

View File

@ -5349,6 +5349,32 @@ TEST_F(WebRtcVideoChannelTest,
stream->GetVideoStreams()[0].max_bitrate_bps);
}
TEST_F(WebRtcVideoChannelTest, SetMaxFramerateOneStream) {
FakeVideoSendStream* stream = AddSendStream();
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
EXPECT_EQ(1UL, parameters.encodings.size());
EXPECT_FALSE(parameters.encodings[0].max_framerate.has_value());
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
// Note that this is testing the behavior of the FakeVideoSendStream, which
// also calls to CreateEncoderStreams to get the VideoStreams, so essentially
// we are just testing the behavior of
// EncoderStreamFactory::CreateEncoderStreams.
ASSERT_EQ(1UL, stream->GetVideoStreams().size());
EXPECT_EQ(kDefaultVideoMaxFramerate,
stream->GetVideoStreams()[0].max_framerate);
// Set max framerate and check that VideoStream.max_framerate is set.
const int kNewMaxFramerate = kDefaultVideoMaxFramerate - 1;
parameters = channel_->GetRtpSendParameters(last_ssrc_);
parameters.encodings[0].max_framerate = kNewMaxFramerate;
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
ASSERT_EQ(1UL, stream->GetVideoStreams().size());
EXPECT_EQ(kNewMaxFramerate, stream->GetVideoStreams()[0].max_framerate);
}
TEST_F(WebRtcVideoChannelTest,
CannotSetRtpSendParametersWithIncorrectNumberOfEncodings) {
AddSendStream();
@ -5501,6 +5527,120 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) {
EXPECT_TRUE(channel_->SetVideoSend(primary_ssrc, nullptr, nullptr));
}
TEST_F(WebRtcVideoChannelTest, GetAndSetRtpSendParametersMaxFramerate) {
const size_t kNumSimulcastStreams = 3;
SetUpSimulcast(true, false);
// Get and set the rtp encoding parameters.
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
for (const auto& encoding : parameters.encodings) {
EXPECT_FALSE(encoding.max_framerate);
}
// Change the value and set it on the VideoChannel.
parameters.encodings[0].max_framerate = 10;
parameters.encodings[1].max_framerate = 20;
parameters.encodings[2].max_framerate = 25;
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
// Verify that the bitrates are set on the VideoChannel.
parameters = channel_->GetRtpSendParameters(last_ssrc_);
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
EXPECT_EQ(10, parameters.encodings[0].max_framerate);
EXPECT_EQ(20, parameters.encodings[1].max_framerate);
EXPECT_EQ(25, parameters.encodings[2].max_framerate);
}
TEST_F(WebRtcVideoChannelTest, MaxSimulcastFrameratePropagatedToEncoder) {
const size_t kNumSimulcastStreams = 3;
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
// Send a full size frame so all simulcast layers are used when reconfiguring.
FakeVideoCapturerWithTaskQueue capturer;
VideoOptions options;
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
EXPECT_EQ(cricket::CS_RUNNING,
capturer.Start(capturer.GetSupportedFormats()->front()));
channel_->SetSend(true);
EXPECT_TRUE(capturer.CaptureFrame());
// Get and set the rtp encoding parameters.
// Change the value and set it on the VideoChannel.
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
parameters.encodings[0].max_framerate = 15;
parameters.encodings[1].max_framerate = 25;
parameters.encodings[2].max_framerate = 20;
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
// Verify that the new value propagated down to the encoder.
// Check that WebRtcVideoSendStream updates VideoEncoderConfig correctly.
EXPECT_EQ(2, stream->num_encoder_reconfigurations());
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy();
EXPECT_EQ(kNumSimulcastStreams, encoder_config.number_of_streams);
EXPECT_EQ(kNumSimulcastStreams, encoder_config.simulcast_layers.size());
EXPECT_EQ(15, encoder_config.simulcast_layers[0].max_framerate);
EXPECT_EQ(25, encoder_config.simulcast_layers[1].max_framerate);
EXPECT_EQ(20, encoder_config.simulcast_layers[2].max_framerate);
// FakeVideoSendStream calls CreateEncoderStreams, test that the vector of
// VideoStreams are created appropriately for the simulcast case.
// Currently the maximum |max_framerate| is used.
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
EXPECT_EQ(25, stream->GetVideoStreams()[0].max_framerate);
EXPECT_EQ(25, stream->GetVideoStreams()[1].max_framerate);
EXPECT_EQ(25, stream->GetVideoStreams()[2].max_framerate);
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
}
TEST_F(WebRtcVideoChannelTest,
DefaultValuePropagatedToEncoderForUnsetFramerate) {
const size_t kNumSimulcastStreams = 3;
const std::vector<webrtc::VideoStream> kDefault = GetSimulcastBitrates720p();
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
// Send a full size frame so all simulcast layers are used when reconfiguring.
FakeVideoCapturerWithTaskQueue capturer;
VideoOptions options;
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
EXPECT_EQ(cricket::CS_RUNNING,
capturer.Start(capturer.GetSupportedFormats()->front()));
channel_->SetSend(true);
EXPECT_TRUE(capturer.CaptureFrame());
// Get and set the rtp encoding parameters.
// Change the value and set it on the VideoChannel.
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
parameters.encodings[0].max_framerate = 15;
parameters.encodings[2].max_framerate = 20;
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
// Verify that the new value propagated down to the encoder.
// Check that WebRtcVideoSendStream updates VideoEncoderConfig correctly.
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy();
EXPECT_EQ(kNumSimulcastStreams, encoder_config.number_of_streams);
EXPECT_EQ(kNumSimulcastStreams, encoder_config.simulcast_layers.size());
EXPECT_EQ(15, encoder_config.simulcast_layers[0].max_framerate);
EXPECT_EQ(-1, encoder_config.simulcast_layers[1].max_framerate);
EXPECT_EQ(20, encoder_config.simulcast_layers[2].max_framerate);
// FakeVideoSendStream calls CreateEncoderStreams, test that the vector of
// VideoStreams are created appropriately for the simulcast case.
// The maximum |max_framerate| is used, kDefaultVideoMaxFramerate: 60.
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
EXPECT_EQ(kDefaultVideoMaxFramerate,
stream->GetVideoStreams()[0].max_framerate);
EXPECT_EQ(kDefaultVideoMaxFramerate,
stream->GetVideoStreams()[1].max_framerate);
EXPECT_EQ(kDefaultVideoMaxFramerate,
stream->GetVideoStreams()[2].max_framerate);
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
}
TEST_F(WebRtcVideoChannelTest, GetAndSetRtpSendParametersMinAndMaxBitrate) {
const size_t kNumSimulcastStreams = 3;
SetUpSimulcast(true, false);