Implemented AutoMuter in MediaOptimization
Also added a unittest. This is the first step towards creating an AutoMuter function in WebRTC. R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2294005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4857 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
04b61790d1
commit
544b17c6a9
@ -204,6 +204,7 @@
|
||||
'video_coding/main/interface/mock/mock_vcm_callbacks.h',
|
||||
'video_coding/main/source/decoding_state_unittest.cc',
|
||||
'video_coding/main/source/jitter_buffer_unittest.cc',
|
||||
'video_coding/main/source/media_optimization_unittest.cc',
|
||||
'video_coding/main/source/receiver_unittest.cc',
|
||||
'video_coding/main/source/session_info_unittest.cc',
|
||||
'video_coding/main/source/timing_unittest.cc',
|
||||
|
@ -46,7 +46,11 @@ MediaOptimization::MediaOptimization(int32_t id, Clock* clock)
|
||||
qm_resolution_(new VCMQmResolution()),
|
||||
last_qm_update_time_(0),
|
||||
last_change_time_(0),
|
||||
num_layers_(0) {
|
||||
num_layers_(0),
|
||||
muting_enabled_(false),
|
||||
video_muted_(false),
|
||||
muter_threshold_bps_(0),
|
||||
muter_window_bps_(0) {
|
||||
memset(send_statistics_, 0, sizeof(send_statistics_));
|
||||
memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
|
||||
}
|
||||
@ -189,6 +193,8 @@ uint32_t MediaOptimization::SetTargetRates(uint32_t target_bitrate,
|
||||
content_->ResetShortTermAvgData();
|
||||
}
|
||||
|
||||
CheckAutoMuteConditions();
|
||||
|
||||
return target_bit_rate_;
|
||||
}
|
||||
|
||||
@ -345,7 +351,9 @@ void MediaOptimization::EnableFrameDropper(bool enable) {
|
||||
bool MediaOptimization::DropFrame() {
|
||||
// Leak appropriate number of bytes.
|
||||
frame_dropper_->Leak((uint32_t)(InputFrameRate() + 0.5f));
|
||||
|
||||
if (video_muted_) {
|
||||
return true; // Drop all frames when muted.
|
||||
}
|
||||
return frame_dropper_->DropFrame();
|
||||
}
|
||||
|
||||
@ -410,6 +418,19 @@ int32_t MediaOptimization::SelectQuality() {
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
void MediaOptimization::EnableAutoMuting(int threshold_bps, int window_bps) {
|
||||
assert(threshold_bps > 0 && window_bps >= 0);
|
||||
muter_threshold_bps_ = threshold_bps;
|
||||
muter_window_bps_ = window_bps;
|
||||
muting_enabled_ = true;
|
||||
video_muted_ = false;
|
||||
}
|
||||
|
||||
void MediaOptimization::DisableAutoMuting() {
|
||||
muting_enabled_ = false;
|
||||
video_muted_ = false;
|
||||
}
|
||||
|
||||
// Private methods below this line.
|
||||
|
||||
int MediaOptimization::UpdateProtectionCallback(
|
||||
@ -584,5 +605,23 @@ void MediaOptimization::ProcessIncomingFrameRate(int64_t now) {
|
||||
}
|
||||
}
|
||||
|
||||
void MediaOptimization::CheckAutoMuteConditions() {
|
||||
// Check conditions for AutoMute. |target_bit_rate_| is in bps.
|
||||
if (muting_enabled_) {
|
||||
if (!video_muted_) {
|
||||
// Check if we just went below the threshold.
|
||||
if (target_bit_rate_ < muter_threshold_bps_) {
|
||||
video_muted_ = true;
|
||||
}
|
||||
} else {
|
||||
// Video is already muted. Check if we just went over the threshold
|
||||
// with a margin.
|
||||
if (target_bit_rate_ > muter_threshold_bps_ + muter_window_bps_) {
|
||||
video_muted_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media_optimization
|
||||
} // namespace webrtc
|
||||
|
@ -120,9 +120,18 @@ class MediaOptimization {
|
||||
// Computes new Quality Mode.
|
||||
int32_t SelectQuality();
|
||||
|
||||
// Enables AutoMuter to turn off video when the rate drops below
|
||||
// |threshold_bps|, and turns back on when the rate goes back up above
|
||||
// |threshold_bps| + |window_bps|.
|
||||
void EnableAutoMuting(int threshold_bps, int window_bps);
|
||||
|
||||
// Disables AutoMuter.
|
||||
void DisableAutoMuting();
|
||||
|
||||
// Accessors and mutators.
|
||||
int32_t max_bit_rate() const { return max_bit_rate_; }
|
||||
void set_max_payload_size(int32_t mtu) { max_payload_size_ = mtu; }
|
||||
bool video_muted() const { return video_muted_; }
|
||||
|
||||
private:
|
||||
typedef std::list<EncodedFrameSample> FrameSampleList;
|
||||
@ -152,6 +161,11 @@ class MediaOptimization {
|
||||
|
||||
void ProcessIncomingFrameRate(int64_t now);
|
||||
|
||||
// Checks conditions for AutoMute. The method compares |target_bit_rate_|
|
||||
// with the threshold values for AutoMute, and changes the state of
|
||||
// |video_muted_| accordingly.
|
||||
void CheckAutoMuteConditions();
|
||||
|
||||
int32_t id_;
|
||||
Clock* clock_;
|
||||
int32_t max_bit_rate_;
|
||||
@ -165,7 +179,7 @@ class MediaOptimization {
|
||||
uint32_t send_statistics_[4];
|
||||
uint32_t send_statistics_zero_encode_;
|
||||
int32_t max_payload_size_;
|
||||
uint32_t target_bit_rate_;
|
||||
int target_bit_rate_;
|
||||
float incoming_frame_rate_;
|
||||
int64_t incoming_frame_times_[kFrameCountHistorySize];
|
||||
bool enable_qm_;
|
||||
@ -181,6 +195,10 @@ class MediaOptimization {
|
||||
int64_t last_qm_update_time_;
|
||||
int64_t last_change_time_; // Content/user triggered.
|
||||
int num_layers_;
|
||||
bool muting_enabled_;
|
||||
bool video_muted_;
|
||||
int muter_threshold_bps_;
|
||||
int muter_window_bps_;
|
||||
}; // End of MediaOptimization class declaration.
|
||||
|
||||
} // namespace media_optimization
|
||||
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/video_coding/main/source/media_optimization.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace media_optimization {
|
||||
|
||||
class TestMediaOptimization : public ::testing::Test {
|
||||
protected:
|
||||
enum {
|
||||
kId = 4711 // Id number for the MediaOptimization class.
|
||||
};
|
||||
enum {
|
||||
kSampleRate = 90000 // RTP timestamps per second.
|
||||
};
|
||||
|
||||
// Note: simulated clock starts at 1 seconds, since parts of webrtc use 0 as
|
||||
// a special case (e.g. frame rate in media optimization).
|
||||
TestMediaOptimization()
|
||||
: clock_(1000),
|
||||
media_opt_(kId, &clock_),
|
||||
frame_time_ms_(33),
|
||||
next_timestamp_(0) {}
|
||||
|
||||
// This method mimics what happens in VideoSender::AddVideoFrame.
|
||||
void AddFrameAndAdvanceTime(int bitrate_bps, bool expect_frame_drop) {
|
||||
ASSERT_GE(bitrate_bps, 0);
|
||||
media_opt_.UpdateIncomingFrameRate();
|
||||
bool frame_dropped = media_opt_.DropFrame();
|
||||
EXPECT_EQ(expect_frame_drop, frame_dropped);
|
||||
if (!frame_dropped) {
|
||||
int bytes_per_frame = bitrate_bps * frame_time_ms_ / (8 * 1000);
|
||||
ASSERT_EQ(VCM_OK, media_opt_.UpdateWithEncodedData(
|
||||
bytes_per_frame, next_timestamp_, kVideoFrameDelta));
|
||||
}
|
||||
next_timestamp_ += frame_time_ms_ * kSampleRate / 1000;
|
||||
clock_.AdvanceTimeMilliseconds(frame_time_ms_);
|
||||
}
|
||||
|
||||
SimulatedClock clock_;
|
||||
MediaOptimization media_opt_;
|
||||
int frame_time_ms_;
|
||||
uint32_t next_timestamp_;
|
||||
};
|
||||
|
||||
|
||||
TEST_F(TestMediaOptimization, VerifyMuting) {
|
||||
// Enable video muter with these limits.
|
||||
// Mute the video when the rate is below 50 kbps and unmute when it gets above
|
||||
// 50 + 10 kbps again.
|
||||
const int kThresholdBps = 50000;
|
||||
const int kWindowBps = 10000;
|
||||
media_opt_.EnableAutoMuting(kThresholdBps, kWindowBps);
|
||||
|
||||
// The video should not be muted from the start.
|
||||
EXPECT_FALSE(media_opt_.video_muted());
|
||||
|
||||
int target_bitrate_kbps = 100;
|
||||
media_opt_.SetTargetRates(target_bitrate_kbps * 1000,
|
||||
0, // Lossrate.
|
||||
100); // RTT in ms.
|
||||
media_opt_.EnableFrameDropper(true);
|
||||
for (int time = 0; time < 2000; time += frame_time_ms_) {
|
||||
ASSERT_NO_FATAL_FAILURE(AddFrameAndAdvanceTime(target_bitrate_kbps, false));
|
||||
}
|
||||
|
||||
// Set the target rate below the limit for muting.
|
||||
media_opt_.SetTargetRates(kThresholdBps - 1000,
|
||||
0, // Lossrate.
|
||||
100); // RTT in ms.
|
||||
// Expect the muter to engage immediately and stay muted.
|
||||
// Test during 2 seconds.
|
||||
for (int time = 0; time < 2000; time += frame_time_ms_) {
|
||||
EXPECT_TRUE(media_opt_.video_muted());
|
||||
ASSERT_NO_FATAL_FAILURE(AddFrameAndAdvanceTime(target_bitrate_kbps, true));
|
||||
}
|
||||
|
||||
// Set the target above the limit for muting, but not above the
|
||||
// limit + window.
|
||||
media_opt_.SetTargetRates(kThresholdBps + 1000,
|
||||
0, // Lossrate.
|
||||
100); // RTT in ms.
|
||||
// Expect the muter to stay muted.
|
||||
// Test during 2 seconds.
|
||||
for (int time = 0; time < 2000; time += frame_time_ms_) {
|
||||
EXPECT_TRUE(media_opt_.video_muted());
|
||||
ASSERT_NO_FATAL_FAILURE(AddFrameAndAdvanceTime(target_bitrate_kbps, true));
|
||||
}
|
||||
|
||||
// Set the target above limit + window.
|
||||
media_opt_.SetTargetRates(kThresholdBps + kWindowBps + 1000,
|
||||
0, // Lossrate.
|
||||
100); // RTT in ms.
|
||||
// Expect the muter to disengage immediately.
|
||||
// Test during 2 seconds.
|
||||
for (int time = 0; time < 2000; time += frame_time_ms_) {
|
||||
EXPECT_FALSE(media_opt_.video_muted());
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
AddFrameAndAdvanceTime((kThresholdBps + kWindowBps) / 1000, false));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media_optimization
|
||||
} // namespace webrtc
|
Loading…
x
Reference in New Issue
Block a user