Move kMinPixelsPerFrame constant in VideoStreamEncoder to VideoEncoder::ScalingSettings.
Make it possible for forced VP8 SW fallback encoder to set min_pixels_per_frame via GetScalingSettings(). Add a min required resolution (in addition to bitrate) before releasing forced SW fallback. BUG=webrtc:6634 Review-Url: https://codereview.webrtc.org/3000693003 Cr-Commit-Position: refs/heads/master@{#19390}
This commit is contained in:
@ -64,6 +64,17 @@ VideoEncoder::ScalingSettings::ScalingSettings(bool on, int low, int high)
|
|||||||
: enabled(on),
|
: enabled(on),
|
||||||
thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))) {}
|
thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))) {}
|
||||||
|
|
||||||
|
VideoEncoder::ScalingSettings::ScalingSettings(bool on,
|
||||||
|
int low,
|
||||||
|
int high,
|
||||||
|
int min_pixels)
|
||||||
|
: enabled(on),
|
||||||
|
thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))),
|
||||||
|
min_pixels_per_frame(min_pixels) {}
|
||||||
|
|
||||||
|
VideoEncoder::ScalingSettings::ScalingSettings(bool on, int min_pixels)
|
||||||
|
: enabled(on), min_pixels_per_frame(min_pixels) {}
|
||||||
|
|
||||||
VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {}
|
VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {}
|
||||||
|
|
||||||
VideoEncoder::ScalingSettings::~ScalingSettings() {}
|
VideoEncoder::ScalingSettings::~ScalingSettings() {}
|
||||||
|
|||||||
@ -75,12 +75,20 @@ class VideoEncoder {
|
|||||||
};
|
};
|
||||||
struct ScalingSettings {
|
struct ScalingSettings {
|
||||||
ScalingSettings(bool on, int low, int high);
|
ScalingSettings(bool on, int low, int high);
|
||||||
|
ScalingSettings(bool on, int low, int high, int min_pixels);
|
||||||
|
ScalingSettings(bool on, int min_pixels);
|
||||||
explicit ScalingSettings(bool on);
|
explicit ScalingSettings(bool on);
|
||||||
ScalingSettings(const ScalingSettings&);
|
ScalingSettings(const ScalingSettings&);
|
||||||
~ScalingSettings();
|
~ScalingSettings();
|
||||||
|
|
||||||
const bool enabled;
|
const bool enabled;
|
||||||
const rtc::Optional<QpThresholds> thresholds;
|
const rtc::Optional<QpThresholds> thresholds;
|
||||||
|
|
||||||
|
// We will never ask for a resolution lower than this.
|
||||||
|
// TODO(kthelgason): Lower this limit when better testing
|
||||||
|
// on MediaCodec and fallback implementations are in place.
|
||||||
|
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
|
||||||
|
const int min_pixels_per_frame = 320 * 180;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VideoCodecVP8 GetDefaultVp8Settings();
|
static VideoCodecVP8 GetDefaultVp8Settings();
|
||||||
|
|||||||
@ -50,12 +50,14 @@ void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps,
|
|||||||
int low_kbps;
|
int low_kbps;
|
||||||
int high_kbps;
|
int high_kbps;
|
||||||
int min_low_ms;
|
int min_low_ms;
|
||||||
if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps,
|
int min_pixels;
|
||||||
&min_low_ms) != 3) {
|
if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
|
||||||
|
&min_low_ms, &min_pixels) != 4) {
|
||||||
LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided.";
|
LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) {
|
if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
|
||||||
|
high_kbps <= low_kbps) {
|
||||||
LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
|
LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -245,6 +247,8 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
|
|||||||
|
|
||||||
VideoEncoder::ScalingSettings
|
VideoEncoder::ScalingSettings
|
||||||
VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
|
VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
|
||||||
|
if (forced_fallback_possible_ && fallback_encoder_)
|
||||||
|
return fallback_encoder_->GetScalingSettings();
|
||||||
return encoder_->GetScalingSettings();
|
return encoder_->GetScalingSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,8 +276,10 @@ bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() {
|
|||||||
if (!IsForcedFallbackActive())
|
if (!IsForcedFallbackActive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps()))
|
if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps(),
|
||||||
|
codec_settings_)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Release the forced fallback encoder.
|
// Release the forced fallback encoder.
|
||||||
if (encoder_->InitEncode(&codec_settings_, number_of_cores_,
|
if (encoder_->InitEncode(&codec_settings_, number_of_cores_,
|
||||||
@ -343,8 +349,10 @@ bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStart(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop(
|
bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop(
|
||||||
uint32_t bitrate_kbps) const {
|
uint32_t bitrate_kbps,
|
||||||
return bitrate_kbps >= high_kbps;
|
const VideoCodec& codec) const {
|
||||||
|
return bitrate_kbps >= high_kbps &&
|
||||||
|
(codec.width * codec.height >= kMinPixelsStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -52,22 +52,24 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder {
|
|||||||
// If |forced_fallback_possible_| is true:
|
// If |forced_fallback_possible_| is true:
|
||||||
// The forced fallback is requested if the target bitrate is below |low_kbps|
|
// The forced fallback is requested if the target bitrate is below |low_kbps|
|
||||||
// for more than |min_low_ms| and the input video resolution is not larger
|
// for more than |min_low_ms| and the input video resolution is not larger
|
||||||
// than |kMaxPixels|.
|
// than |kMaxPixelsStart|.
|
||||||
// If the bitrate is above |high_kbps|, the forced fallback is requested to
|
// If the bitrate is above |high_kbps| and the resolution is not smaller than
|
||||||
// immediately be stopped.
|
// |kMinPixelsStop|, the forced fallback is requested to immediately be
|
||||||
|
// stopped.
|
||||||
class ForcedFallbackParams {
|
class ForcedFallbackParams {
|
||||||
public:
|
public:
|
||||||
bool ShouldStart(uint32_t bitrate_kbps, const VideoCodec& codec);
|
bool ShouldStart(uint32_t bitrate_kbps, const VideoCodec& codec);
|
||||||
bool ShouldStop(uint32_t bitrate_kbps) const;
|
bool ShouldStop(uint32_t bitrate_kbps, const VideoCodec& codec) const;
|
||||||
void Reset() { start_ms.reset(); }
|
void Reset() { start_ms.reset(); }
|
||||||
bool IsValid(const VideoCodec& codec) const {
|
bool IsValid(const VideoCodec& codec) const {
|
||||||
return codec.width * codec.height <= kMaxPixels;
|
return codec.width * codec.height <= kMaxPixelsStart;
|
||||||
}
|
}
|
||||||
rtc::Optional<int64_t> start_ms; // Set when bitrate is below |low_kbps|.
|
rtc::Optional<int64_t> start_ms; // Set when bitrate is below |low_kbps|.
|
||||||
uint32_t low_kbps = 100;
|
uint32_t low_kbps = 100;
|
||||||
uint32_t high_kbps = 150;
|
uint32_t high_kbps = 150;
|
||||||
int64_t min_low_ms = 10000;
|
int64_t min_low_ms = 10000;
|
||||||
const int kMaxPixels = 320 * 240;
|
const int kMaxPixelsStart = 320 * 240;
|
||||||
|
const int kMinPixelsStop = 320 * 180;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool RequestForcedFallback();
|
bool RequestForcedFallback();
|
||||||
|
|||||||
@ -29,6 +29,7 @@ const int kHeight = 240;
|
|||||||
const int kNumCores = 2;
|
const int kNumCores = 2;
|
||||||
const uint32_t kFramerate = 30;
|
const uint32_t kFramerate = 30;
|
||||||
const size_t kMaxPayloadSize = 800;
|
const size_t kMaxPayloadSize = 800;
|
||||||
|
const int kDefaultMinPixelsPerFrame = 320 * 180;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
|
class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
|
||||||
@ -93,6 +94,10 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
|
|||||||
return "fake-encoder";
|
return "fake-encoder";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoEncoder::ScalingSettings GetScalingSettings() const override {
|
||||||
|
return VideoEncoder::ScalingSettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
int init_encode_count_ = 0;
|
int init_encode_count_ = 0;
|
||||||
int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
|
int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
|
||||||
int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
|
int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
|
||||||
@ -141,7 +146,8 @@ void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame(int expected_ret) {
|
void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame(int expected_ret) {
|
||||||
rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(kWidth, kHeight);
|
rtc::scoped_refptr<I420Buffer> buffer =
|
||||||
|
I420Buffer::Create(codec_.width, codec_.height);
|
||||||
I420Buffer::SetBlack(buffer);
|
I420Buffer::SetBlack(buffer);
|
||||||
std::vector<FrameType> types(1, kVideoFrameKey);
|
std::vector<FrameType> types(1, kVideoFrameKey);
|
||||||
|
|
||||||
@ -299,9 +305,10 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
|
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
|
||||||
VideoCodec codec = {};
|
codec_.width = kWidth;
|
||||||
|
codec_.height = kHeight;
|
||||||
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
|
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
|
||||||
fallback_wrapper_.InitEncode(&codec, kNumCores, kMaxPayloadSize);
|
fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize);
|
||||||
EncodeFrame();
|
EncodeFrame();
|
||||||
CheckLastEncoderName("fake-encoder");
|
CheckLastEncoderName("fake-encoder");
|
||||||
}
|
}
|
||||||
@ -318,6 +325,8 @@ namespace {
|
|||||||
const int kLowKbps = 220;
|
const int kLowKbps = 220;
|
||||||
const int kHighKbps = 300;
|
const int kHighKbps = 300;
|
||||||
const int kMinLowDurationMs = 4000;
|
const int kMinLowDurationMs = 4000;
|
||||||
|
const int kMinPixelsPerFrame = 1;
|
||||||
|
const int kMinPixelsStop = 320 * 180;
|
||||||
const std::string kFieldTrial = "WebRTC-VP8-Forced-Fallback-Encoder";
|
const std::string kFieldTrial = "WebRTC-VP8-Forced-Fallback-Encoder";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -350,6 +359,8 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest {
|
|||||||
codec_.width = kWidth;
|
codec_.width = kWidth;
|
||||||
codec_.height = kHeight;
|
codec_.height = kHeight;
|
||||||
codec_.VP8()->numberOfTemporalLayers = 1;
|
codec_.VP8()->numberOfTemporalLayers = 1;
|
||||||
|
codec_.VP8()->automaticResizeOn = true;
|
||||||
|
codec_.VP8()->frameDroppingOn = true;
|
||||||
codec_.VP8()->tl_factory = tl_factory.get();
|
codec_.VP8()->tl_factory = tl_factory.get();
|
||||||
rate_allocator_.reset(
|
rate_allocator_.reset(
|
||||||
new SimulcastRateAllocator(codec_, std::move(tl_factory)));
|
new SimulcastRateAllocator(codec_, std::move(tl_factory)));
|
||||||
@ -381,7 +392,8 @@ class ForcedFallbackTestEnabled : public ForcedFallbackTest {
|
|||||||
: ForcedFallbackTest(kFieldTrial + "/Enabled-" +
|
: ForcedFallbackTest(kFieldTrial + "/Enabled-" +
|
||||||
std::to_string(kLowKbps) + "," +
|
std::to_string(kLowKbps) + "," +
|
||||||
std::to_string(kHighKbps) + "," +
|
std::to_string(kHighKbps) + "," +
|
||||||
std::to_string(kMinLowDurationMs) + "/") {}
|
std::to_string(kMinLowDurationMs) + "," +
|
||||||
|
std::to_string(kMinPixelsPerFrame) + "/") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ForcedFallbackTestDisabled : public ForcedFallbackTest {
|
class ForcedFallbackTestDisabled : public ForcedFallbackTest {
|
||||||
@ -575,4 +587,58 @@ TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedForNonValidSettings) {
|
|||||||
EncodeFrameAndVerifyLastName("fake-encoder");
|
EncodeFrameAndVerifyLastName("fake-encoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithoutFallback) {
|
||||||
|
// Bitrate at low threshold.
|
||||||
|
SetRateAllocation(kLowKbps);
|
||||||
|
EncodeFrameAndVerifyLastName("fake-encoder");
|
||||||
|
// Default min pixels per frame should be used.
|
||||||
|
const auto settings = fallback_wrapper_.GetScalingSettings();
|
||||||
|
EXPECT_TRUE(settings.enabled);
|
||||||
|
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithFallback) {
|
||||||
|
// Bitrate at low threshold.
|
||||||
|
SetRateAllocation(kLowKbps);
|
||||||
|
EncodeFrameAndVerifyLastName("fake-encoder");
|
||||||
|
// Duration passed, expect fallback.
|
||||||
|
clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs));
|
||||||
|
EncodeFrameAndVerifyLastName("libvpx");
|
||||||
|
// Configured min pixels per frame should be used.
|
||||||
|
const auto settings = fallback_wrapper_.GetScalingSettings();
|
||||||
|
EXPECT_TRUE(settings.enabled);
|
||||||
|
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ForcedFallbackTestEnabled, FallbackIsKeptIfResolutionIsTooSmall) {
|
||||||
|
// Bitrate at low threshold.
|
||||||
|
SetRateAllocation(kLowKbps);
|
||||||
|
EncodeFrameAndVerifyLastName("fake-encoder");
|
||||||
|
// Duration passed, expect fallback.
|
||||||
|
clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs));
|
||||||
|
EncodeFrameAndVerifyLastName("libvpx");
|
||||||
|
|
||||||
|
// Re-initialize encoder with a resolution less than |kMinPixelsStop|.
|
||||||
|
codec_.height = kMinPixelsStop / codec_.width - 1;
|
||||||
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize));
|
||||||
|
EXPECT_EQ(1, fake_encoder_.init_encode_count_); // No change
|
||||||
|
SetRateAllocation(kHighKbps - 1);
|
||||||
|
EncodeFrameAndVerifyLastName("libvpx");
|
||||||
|
// Bitrate at high threshold but resolution too small for fallback to end.
|
||||||
|
SetRateAllocation(kHighKbps);
|
||||||
|
EncodeFrameAndVerifyLastName("libvpx");
|
||||||
|
|
||||||
|
// Re-initialize encoder with a resolution equal to |kMinPixelsStop|.
|
||||||
|
codec_.height++;
|
||||||
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize));
|
||||||
|
EXPECT_EQ(1, fake_encoder_.init_encode_count_); // No change
|
||||||
|
SetRateAllocation(kHighKbps - 1);
|
||||||
|
EncodeFrameAndVerifyLastName("libvpx");
|
||||||
|
// Bitrate at high threshold and resolution large enough for fallback to end.
|
||||||
|
SetRateAllocation(kHighKbps);
|
||||||
|
EncodeFrameAndVerifyLastName("fake-encoder");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -464,6 +464,7 @@ if (rtc_include_tests) {
|
|||||||
"../../api:video_frame_api",
|
"../../api:video_frame_api",
|
||||||
"../../common_video:common_video",
|
"../../common_video:common_video",
|
||||||
"../../rtc_base:rtc_base_approved",
|
"../../rtc_base:rtc_base_approved",
|
||||||
|
"../../test:field_trial",
|
||||||
"../../test:test_support",
|
"../../test:test_support",
|
||||||
"../../test:video_test_common",
|
"../../test:video_test_common",
|
||||||
"../video_capture",
|
"../video_capture",
|
||||||
|
|||||||
@ -20,9 +20,11 @@
|
|||||||
#include "webrtc/rtc_base/checks.h"
|
#include "webrtc/rtc_base/checks.h"
|
||||||
#include "webrtc/rtc_base/optional.h"
|
#include "webrtc/rtc_base/optional.h"
|
||||||
#include "webrtc/rtc_base/timeutils.h"
|
#include "webrtc/rtc_base/timeutils.h"
|
||||||
|
#include "webrtc/test/field_trial.h"
|
||||||
#include "webrtc/test/frame_utils.h"
|
#include "webrtc/test/frame_utils.h"
|
||||||
#include "webrtc/test/gtest.h"
|
#include "webrtc/test/gtest.h"
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
#include "webrtc/test/testsupport/fileutils.h"
|
||||||
|
#include "webrtc/test/video_codec_settings.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -39,6 +41,10 @@ enum { kMaxWaitDecTimeMs = 25 };
|
|||||||
constexpr uint32_t kTestTimestamp = 123;
|
constexpr uint32_t kTestTimestamp = 123;
|
||||||
constexpr int64_t kTestNtpTimeMs = 456;
|
constexpr int64_t kTestNtpTimeMs = 456;
|
||||||
constexpr uint32_t kTimestampIncrementPerFrame = 3000;
|
constexpr uint32_t kTimestampIncrementPerFrame = 3000;
|
||||||
|
constexpr int kNumCores = 1;
|
||||||
|
constexpr size_t kMaxPayloadSize = 1440;
|
||||||
|
constexpr int kMinPixelsPerFrame = 12345;
|
||||||
|
constexpr int kDefaultMinPixelsPerFrame = 320 * 180;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -143,6 +149,10 @@ void Vp8UnitTestDecodeCompleteCallback::Decoded(
|
|||||||
|
|
||||||
class TestVp8Impl : public ::testing::Test {
|
class TestVp8Impl : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
|
TestVp8Impl() : TestVp8Impl("") {}
|
||||||
|
explicit TestVp8Impl(const std::string& field_trials)
|
||||||
|
: override_field_trials_(field_trials) {}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
encoder_.reset(VP8Encoder::Create());
|
encoder_.reset(VP8Encoder::Create());
|
||||||
decoder_.reset(VP8Decoder::Create());
|
decoder_.reset(VP8Decoder::Create());
|
||||||
@ -190,9 +200,11 @@ class TestVp8Impl : public ::testing::Test {
|
|||||||
codec_settings_.VP8()->tl_factory = &tl_factory_;
|
codec_settings_.VP8()->tl_factory = &tl_factory_;
|
||||||
codec_settings_.VP8()->numberOfTemporalLayers = 1;
|
codec_settings_.VP8()->numberOfTemporalLayers = 1;
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
encoder_->InitEncode(&codec_settings_, 1, 1440));
|
decoder_->InitDecode(&codec_settings_, kNumCores));
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WaitForEncodedFrame() const {
|
size_t WaitForEncodedFrame() const {
|
||||||
@ -228,6 +240,7 @@ class TestVp8Impl : public ::testing::Test {
|
|||||||
const int kWidth = 172;
|
const int kWidth = 172;
|
||||||
const int kHeight = 144;
|
const int kHeight = 144;
|
||||||
|
|
||||||
|
test::ScopedFieldTrials override_field_trials_;
|
||||||
std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_;
|
std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_;
|
||||||
std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_;
|
std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_;
|
||||||
std::unique_ptr<uint8_t[]> source_buffer_;
|
std::unique_ptr<uint8_t[]> source_buffer_;
|
||||||
@ -266,12 +279,13 @@ TEST_F(TestVp8Impl, EncoderParameterTest) {
|
|||||||
codec_settings_.maxFramerate));
|
codec_settings_.maxFramerate));
|
||||||
|
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
encoder_->InitEncode(&codec_settings_, 1, 1440));
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
|
||||||
// Decoder parameter tests.
|
// Decoder parameter tests.
|
||||||
// Calls before InitDecode().
|
// Calls before InitDecode().
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release());
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release());
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1));
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
decoder_->InitDecode(&codec_settings_, kNumCores));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only test the encoder here, since the decoded frame rotation is set based
|
// We only test the encoder here, since the decoded frame rotation is set based
|
||||||
@ -374,7 +388,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
|
|||||||
// Override default settings.
|
// Override default settings.
|
||||||
codec_settings_.VP8()->numberOfTemporalLayers = 2;
|
codec_settings_.VP8()->numberOfTemporalLayers = 2;
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
encoder_->InitEncode(&codec_settings_, 1, 1440));
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
|
||||||
// Temporal layer 0.
|
// Temporal layer 0.
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
@ -410,7 +424,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
|
|||||||
// Reinit.
|
// Reinit.
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release());
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release());
|
||||||
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
encoder_->InitEncode(&codec_settings_, 1, 1440));
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
|
||||||
// Temporal layer 0.
|
// Temporal layer 0.
|
||||||
input_frame_->set_timestamp(input_frame_->timestamp() +
|
input_frame_->set_timestamp(input_frame_->timestamp() +
|
||||||
@ -445,4 +459,46 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
|
|||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TestVp8Impl, ScalingDisabledIfAutomaticResizeOff) {
|
||||||
|
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
|
||||||
|
codec_settings_.VP8()->tl_factory = &tl_factory_;
|
||||||
|
codec_settings_.VP8()->automaticResizeOn = false;
|
||||||
|
|
||||||
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
|
||||||
|
EXPECT_FALSE(settings.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) {
|
||||||
|
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
|
||||||
|
codec_settings_.VP8()->tl_factory = &tl_factory_;
|
||||||
|
codec_settings_.VP8()->automaticResizeOn = true;
|
||||||
|
|
||||||
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
|
||||||
|
EXPECT_TRUE(settings.enabled);
|
||||||
|
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestVp8ImplWithForcedFallbackEnabled : public TestVp8Impl {
|
||||||
|
public:
|
||||||
|
TestVp8ImplWithForcedFallbackEnabled()
|
||||||
|
: TestVp8Impl("WebRTC-VP8-Forced-Fallback-Encoder/Enabled-1,2,3," +
|
||||||
|
std::to_string(kMinPixelsPerFrame) + "/") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TestVp8ImplWithForcedFallbackEnabled, MinPixelsPerFrameConfigured) {
|
||||||
|
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
|
||||||
|
codec_settings_.VP8()->tl_factory = &tl_factory_;
|
||||||
|
codec_settings_.VP8()->automaticResizeOn = true;
|
||||||
|
|
||||||
|
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
||||||
|
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
|
||||||
|
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
|
||||||
|
EXPECT_TRUE(settings.enabled);
|
||||||
|
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -42,6 +42,8 @@ namespace {
|
|||||||
|
|
||||||
const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Arm";
|
const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Arm";
|
||||||
const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost";
|
const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost";
|
||||||
|
const char kVp8ForceFallbackEncoderFieldTrial[] =
|
||||||
|
"WebRTC-VP8-Forced-Fallback-Encoder";
|
||||||
|
|
||||||
const int kTokenPartitions = VP8_ONE_TOKENPARTITION;
|
const int kTokenPartitions = VP8_ONE_TOKENPARTITION;
|
||||||
enum { kVp8ErrorPropagationTh = 30 };
|
enum { kVp8ErrorPropagationTh = 30 };
|
||||||
@ -110,6 +112,31 @@ int NumStreamsDisabled(const std::vector<bool>& streams) {
|
|||||||
return num_disabled;
|
return num_disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc::Optional<int> GetForcedFallbackMinPixelsFromFieldTrialGroup() {
|
||||||
|
if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial))
|
||||||
|
return rtc::Optional<int>();
|
||||||
|
|
||||||
|
std::string group =
|
||||||
|
webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
|
||||||
|
if (group.empty())
|
||||||
|
return rtc::Optional<int>();
|
||||||
|
|
||||||
|
int low_kbps;
|
||||||
|
int high_kbps;
|
||||||
|
int min_low_ms;
|
||||||
|
int min_pixels;
|
||||||
|
if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
|
||||||
|
&min_low_ms, &min_pixels) != 4) {
|
||||||
|
return rtc::Optional<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
|
||||||
|
high_kbps <= low_kbps) {
|
||||||
|
return rtc::Optional<int>();
|
||||||
|
}
|
||||||
|
return rtc::Optional<int>(min_pixels);
|
||||||
|
}
|
||||||
|
|
||||||
bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) {
|
bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) {
|
||||||
std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial);
|
std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial);
|
||||||
if (group.empty())
|
if (group.empty())
|
||||||
@ -181,6 +208,7 @@ vpx_enc_frame_flags_t VP8EncoderImpl::EncodeFlags(
|
|||||||
|
|
||||||
VP8EncoderImpl::VP8EncoderImpl()
|
VP8EncoderImpl::VP8EncoderImpl()
|
||||||
: use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)),
|
: use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)),
|
||||||
|
min_pixels_per_frame_(GetForcedFallbackMinPixelsFromFieldTrialGroup()),
|
||||||
encoded_complete_callback_(nullptr),
|
encoded_complete_callback_(nullptr),
|
||||||
inited_(false),
|
inited_(false),
|
||||||
timestamp_(0),
|
timestamp_(0),
|
||||||
@ -935,6 +963,10 @@ VideoEncoder::ScalingSettings VP8EncoderImpl::GetScalingSettings() const {
|
|||||||
const bool enable_scaling = encoders_.size() == 1 &&
|
const bool enable_scaling = encoders_.size() == 1 &&
|
||||||
configurations_[0].rc_dropframe_thresh > 0 &&
|
configurations_[0].rc_dropframe_thresh > 0 &&
|
||||||
codec_.VP8().automaticResizeOn;
|
codec_.VP8().automaticResizeOn;
|
||||||
|
if (enable_scaling && min_pixels_per_frame_) {
|
||||||
|
return VideoEncoder::ScalingSettings(enable_scaling,
|
||||||
|
*min_pixels_per_frame_);
|
||||||
|
}
|
||||||
return VideoEncoder::ScalingSettings(enable_scaling);
|
return VideoEncoder::ScalingSettings(enable_scaling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,6 +94,7 @@ class VP8EncoderImpl : public VP8Encoder {
|
|||||||
uint32_t MaxIntraTarget(uint32_t optimal_buffer_size);
|
uint32_t MaxIntraTarget(uint32_t optimal_buffer_size);
|
||||||
|
|
||||||
const bool use_gf_boost_;
|
const bool use_gf_boost_;
|
||||||
|
const rtc::Optional<int> min_pixels_per_frame_;
|
||||||
|
|
||||||
EncodedImageCallback* encoded_complete_callback_;
|
EncodedImageCallback* encoded_complete_callback_;
|
||||||
VideoCodec codec_;
|
VideoCodec codec_;
|
||||||
|
|||||||
@ -38,12 +38,6 @@ namespace {
|
|||||||
|
|
||||||
// Time interval for logging frame counts.
|
// Time interval for logging frame counts.
|
||||||
const int64_t kFrameLogIntervalMs = 60000;
|
const int64_t kFrameLogIntervalMs = 60000;
|
||||||
|
|
||||||
// We will never ask for a resolution lower than this.
|
|
||||||
// TODO(kthelgason): Lower this limit when better testing
|
|
||||||
// on MediaCodec and fallback implementations are in place.
|
|
||||||
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
|
|
||||||
const int kMinPixelsPerFrame = 320 * 180;
|
|
||||||
const int kMinFramerateFps = 2;
|
const int kMinFramerateFps = 2;
|
||||||
const int kMaxFramerateFps = 120;
|
const int kMaxFramerateFps = 120;
|
||||||
|
|
||||||
@ -233,7 +227,7 @@ class VideoStreamEncoder::VideoSourceProxy {
|
|||||||
source_->AddOrUpdateSink(video_stream_encoder_, sink_wants_);
|
source_->AddOrUpdateSink(video_stream_encoder_, sink_wants_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RequestResolutionLowerThan(int pixel_count) {
|
bool RequestResolutionLowerThan(int pixel_count, int min_pixels_per_frame) {
|
||||||
// Called on the encoder task queue.
|
// Called on the encoder task queue.
|
||||||
rtc::CritScope lock(&crit_);
|
rtc::CritScope lock(&crit_);
|
||||||
if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
|
if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
|
||||||
@ -244,7 +238,7 @@ class VideoStreamEncoder::VideoSourceProxy {
|
|||||||
// The input video frame size will have a resolution less than or equal to
|
// The input video frame size will have a resolution less than or equal to
|
||||||
// |max_pixel_count| depending on how the source can scale the frame size.
|
// |max_pixel_count| depending on how the source can scale the frame size.
|
||||||
const int pixels_wanted = (pixel_count * 3) / 5;
|
const int pixels_wanted = (pixel_count * 3) / 5;
|
||||||
if (pixels_wanted < kMinPixelsPerFrame ||
|
if (pixels_wanted < min_pixels_per_frame ||
|
||||||
pixels_wanted >= sink_wants_.max_pixel_count) {
|
pixels_wanted >= sink_wants_.max_pixel_count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -990,7 +984,8 @@ void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
|
|||||||
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
||||||
// Scale down resolution.
|
// Scale down resolution.
|
||||||
if (!source_proxy_->RequestResolutionLowerThan(
|
if (!source_proxy_->RequestResolutionLowerThan(
|
||||||
adaptation_request.input_pixel_count_)) {
|
adaptation_request.input_pixel_count_,
|
||||||
|
settings_.encoder->GetScalingSettings().min_pixels_per_frame)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GetAdaptCounter().IncrementResolution(reason);
|
GetAdaptCounter().IncrementResolution(reason);
|
||||||
|
|||||||
@ -29,8 +29,6 @@
|
|||||||
#include "webrtc/video/video_stream_encoder.h"
|
#include "webrtc/video/video_stream_encoder.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// TODO(kthelgason): Lower this limit when better testing
|
|
||||||
// on MediaCodec and fallback implementations are in place.
|
|
||||||
const int kMinPixelsPerFrame = 320 * 180;
|
const int kMinPixelsPerFrame = 320 * 180;
|
||||||
const int kMinFramerateFps = 2;
|
const int kMinFramerateFps = 2;
|
||||||
const int64_t kFrameTimeoutMs = 100;
|
const int64_t kFrameTimeoutMs = 100;
|
||||||
@ -482,7 +480,7 @@ class VideoStreamEncoderTest : public ::testing::Test {
|
|||||||
VideoEncoder::ScalingSettings GetScalingSettings() const override {
|
VideoEncoder::ScalingSettings GetScalingSettings() const override {
|
||||||
rtc::CritScope lock(&local_crit_sect_);
|
rtc::CritScope lock(&local_crit_sect_);
|
||||||
if (quality_scaling_)
|
if (quality_scaling_)
|
||||||
return VideoEncoder::ScalingSettings(true, 1, 2);
|
return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
|
||||||
return VideoEncoder::ScalingSettings(false);
|
return VideoEncoder::ScalingSettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1909,7 +1907,7 @@ TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
|
|||||||
video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||||
|
|
||||||
// Enable adapter, expected input resolutions when downscaling:
|
// Enable adapter, expected input resolutions when downscaling:
|
||||||
// 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
|
// 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
|
||||||
video_source_.set_adaptation_enabled(true);
|
video_source_.set_adaptation_enabled(true);
|
||||||
|
|
||||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||||
|
|||||||
Reference in New Issue
Block a user