Adding a max jitter filter to the JB estimate - allowing two modes, one will return the last estimate (current setting), and another will return the max value seen, and allow setting an initial value.
This cl also includes tests and some clean up. Review URL: https://webrtc-codereview.appspot.com/1019007 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3445 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
e07c661a29
commit
119c67df36
@ -764,21 +764,23 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(VCMEncodedFrame* encoded_frame,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VCMJitterBuffer::EnableMaxJitterEstimate(bool enable,
|
||||
uint32_t initial_delay_ms) {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
jitter_estimate_.EnableMaxJitterEstimate(enable, initial_delay_ms);
|
||||
}
|
||||
|
||||
uint32_t VCMJitterBuffer::EstimatedJitterMs() {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
uint32_t estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
|
||||
|
||||
// Compute RTT multiplier for estimation
|
||||
// Compute RTT multiplier for estimation.
|
||||
// low_rtt_nackThresholdMs_ == -1 means no FEC.
|
||||
double rtt_mult = 1.0f;
|
||||
if (nack_mode_ == kNackHybrid && (low_rtt_nack_threshold_ms_ >= 0 &&
|
||||
static_cast<int>(rtt_ms_) > low_rtt_nack_threshold_ms_)) {
|
||||
// from here we count on FEC
|
||||
// From here we count on FEC.
|
||||
rtt_mult = 0.0f;
|
||||
}
|
||||
estimate += static_cast<uint32_t>
|
||||
(jitter_estimate_.GetJitterEstimate(rtt_mult) + 0.5);
|
||||
return estimate;
|
||||
return jitter_estimate_.GetJitterEstimate(rtt_mult);
|
||||
}
|
||||
|
||||
void VCMJitterBuffer::UpdateRtt(uint32_t rtt_ms) {
|
||||
|
@ -13,16 +13,16 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "modules/interface/module_common_types.h"
|
||||
#include "modules/video_coding/main/interface/video_coding_defines.h"
|
||||
#include "modules/video_coding/main/source/decoding_state.h"
|
||||
#include "modules/video_coding/main/source/event.h"
|
||||
#include "modules/video_coding/main/source/inter_frame_delay.h"
|
||||
#include "modules/video_coding/main/source/jitter_buffer_common.h"
|
||||
#include "modules/video_coding/main/source/jitter_estimator.h"
|
||||
#include "system_wrappers/interface/constructor_magic.h"
|
||||
#include "system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
|
||||
#include "webrtc/modules/video_coding/main/source/decoding_state.h"
|
||||
#include "webrtc/modules/video_coding/main/source/event.h"
|
||||
#include "webrtc/modules/video_coding/main/source/inter_frame_delay.h"
|
||||
#include "webrtc/modules/video_coding/main/source/jitter_buffer_common.h"
|
||||
#include "webrtc/modules/video_coding/main/source/jitter_estimator.h"
|
||||
#include "webrtc/system_wrappers/interface/constructor_magic.h"
|
||||
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -124,6 +124,11 @@ class VCMJitterBuffer {
|
||||
VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame,
|
||||
const VCMPacket& packet);
|
||||
|
||||
// Enable a max filter on the jitter estimate, and setting of the initial
|
||||
// delay (only when in max mode). When disabled (default), the last jitter
|
||||
// estimate will be used.
|
||||
void EnableMaxJitterEstimate(bool enable, uint32_t initial_delay_ms);
|
||||
|
||||
// Returns the estimated jitter in milliseconds.
|
||||
uint32_t EstimatedJitterMs();
|
||||
|
||||
|
@ -11,41 +11,36 @@
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace webrtc {
|
||||
|
||||
enum { kMaxNumberOfFrames = 100 };
|
||||
enum { kStartNumberOfFrames = 6 }; // in packets, 6 packets are approximately 198 ms,
|
||||
// we need at least one more for process
|
||||
enum { kMaxVideoDelayMs = 2000 }; // in ms
|
||||
enum { kStartNumberOfFrames = 6 };
|
||||
enum { kMaxVideoDelayMs = 2000 };
|
||||
|
||||
enum VCMJitterBufferEnum
|
||||
{
|
||||
enum VCMJitterBufferEnum {
|
||||
kMaxConsecutiveOldFrames = 60,
|
||||
kMaxConsecutiveOldPackets = 300,
|
||||
kMaxPacketsInSession = 800,
|
||||
kBufferIncStepSizeBytes = 30000, // >20 packets
|
||||
kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte
|
||||
kBufferIncStepSizeBytes = 30000, // >20 packets.
|
||||
kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte.
|
||||
};
|
||||
|
||||
enum VCMFrameBufferEnum
|
||||
{
|
||||
enum VCMFrameBufferEnum {
|
||||
kStateError = -4,
|
||||
kFlushIndicator = -3, // Indicator that a flush has occurred.
|
||||
kTimeStampError = -2,
|
||||
kSizeError = -1,
|
||||
kNoError = 0,
|
||||
kIncomplete = 1, // Frame incomplete
|
||||
kIncomplete = 1, // Frame incomplete.
|
||||
kFirstPacket = 2,
|
||||
kCompleteSession = 3, // at least one layer in the frame complete.
|
||||
kDecodableSession = 4, // Frame incomplete, but ready to be decoded
|
||||
kDuplicatePacket = 5 // We're receiving a duplicate packet.
|
||||
};
|
||||
|
||||
enum VCMFrameBufferStateEnum
|
||||
{
|
||||
enum VCMFrameBufferStateEnum {
|
||||
kStateFree, // Unused frame in the JB
|
||||
kStateEmpty, // frame popped by the RTP receiver
|
||||
kStateIncomplete, // frame that have one or more packet(s) stored
|
||||
@ -57,8 +52,7 @@ enum VCMFrameBufferStateEnum
|
||||
enum { kH264StartCodeLengthBytes = 4};
|
||||
|
||||
// Used to indicate if a received packet contain a complete NALU (or equivalent)
|
||||
enum VCMNaluCompleteness
|
||||
{
|
||||
enum VCMNaluCompleteness {
|
||||
kNaluUnset = 0, // Packet has not been filled.
|
||||
kNaluComplete = 1, // Packet can be decoded as is.
|
||||
kNaluStart, // Packet contain beginning of NALU
|
||||
@ -78,7 +72,6 @@ WebRtc_UWord32 LatestTimestamp(WebRtc_UWord32 timestamp1,
|
||||
WebRtc_Word32 LatestSequenceNumber(WebRtc_Word32 seq_num1,
|
||||
WebRtc_Word32 seq_num2,
|
||||
bool* has_wrapped);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
|
||||
|
@ -265,6 +265,33 @@ TEST_F(TestRunningJitterBuffer, TestEmptyPackets) {
|
||||
EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0));
|
||||
}
|
||||
|
||||
TEST_F(TestRunningJitterBuffer, JitterEstimateMode) {
|
||||
// Default value (should be in kLastEstimate mode).
|
||||
InsertFrame(kVideoFrameKey);
|
||||
InsertFrame(kVideoFrameDelta);
|
||||
EXPECT_GT(20u, jitter_buffer_->EstimatedJitterMs());
|
||||
// Set kMaxEstimate with a 2 seconds initial delay.
|
||||
jitter_buffer_->EnableMaxJitterEstimate(true, 2000u);
|
||||
EXPECT_EQ(2000u, jitter_buffer_->EstimatedJitterMs());
|
||||
InsertFrame(kVideoFrameDelta);
|
||||
EXPECT_EQ(2000u, jitter_buffer_->EstimatedJitterMs());
|
||||
// Set kMaxEstimate with a 0S initial delay.
|
||||
jitter_buffer_->EnableMaxJitterEstimate(true, 0u);
|
||||
EXPECT_GT(20u, jitter_buffer_->EstimatedJitterMs());
|
||||
// Jitter cannot decrease.
|
||||
InsertFrames(2, kVideoFrameDelta);
|
||||
uint32_t je1 = jitter_buffer_->EstimatedJitterMs();
|
||||
InsertFrames(2, kVideoFrameDelta);
|
||||
EXPECT_GE(je1, jitter_buffer_->EstimatedJitterMs());
|
||||
|
||||
// Set kLastEstimate mode (initial delay is arbitrary in this case and will
|
||||
// be ignored).
|
||||
jitter_buffer_->EnableMaxJitterEstimate(false, 2000u);
|
||||
EXPECT_GT(20u, jitter_buffer_->EstimatedJitterMs());
|
||||
InsertFrames(10, kVideoFrameDelta);
|
||||
EXPECT_GT(20u, jitter_buffer_->EstimatedJitterMs());
|
||||
}
|
||||
|
||||
TEST_F(TestJitterBufferNack, TestEmptyPackets) {
|
||||
// Make sure empty packets doesn't clog the jitter buffer.
|
||||
jitter_buffer_->SetNackMode(kNackHybrid, kLowRttNackMs, -1);
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum { kInitialMaxJitterEstimate = 0 };
|
||||
|
||||
VCMJitterEstimator::VCMJitterEstimator(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId) :
|
||||
_vcmId(vcmId),
|
||||
_receiverId(receiverId),
|
||||
@ -33,7 +35,9 @@ _numStdDevFrameSizeOutlier(3),
|
||||
_noiseStdDevs(2.33), // ~Less than 1% chance
|
||||
// (look up in normal distribution table)...
|
||||
_noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
|
||||
_rttFilter(vcmId, receiverId)
|
||||
_rttFilter(vcmId, receiverId),
|
||||
_jitterEstimateMode(kLastEstimate),
|
||||
_maxJitterEstimateMs(kInitialMaxJitterEstimate)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
@ -62,6 +66,8 @@ VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs)
|
||||
_startupCount = rhs._startupCount;
|
||||
_latestNackTimestamp = rhs._latestNackTimestamp;
|
||||
_nackCount = rhs._nackCount;
|
||||
_jitterEstimateMode = rhs._jitterEstimateMode;
|
||||
_maxJitterEstimateMs = rhs._maxJitterEstimateMs;
|
||||
_rttFilter = rhs._rttFilter;
|
||||
}
|
||||
return *this;
|
||||
@ -95,6 +101,8 @@ VCMJitterEstimator::Reset()
|
||||
_fsSum = 0;
|
||||
_fsCount = 0;
|
||||
_startupCount = 0;
|
||||
_jitterEstimateMode = kLastEstimate;
|
||||
_maxJitterEstimateMs = kInitialMaxJitterEstimate;
|
||||
_rttFilter.Reset();
|
||||
}
|
||||
|
||||
@ -401,21 +409,39 @@ VCMJitterEstimator::UpdateMaxFrameSize(WebRtc_UWord32 frameSizeBytes)
|
||||
}
|
||||
}
|
||||
|
||||
void VCMJitterEstimator::EnableMaxJitterEstimate(bool enable,
|
||||
uint32_t initial_delay_ms)
|
||||
{
|
||||
if (enable) {
|
||||
_maxJitterEstimateMs = initial_delay_ms;
|
||||
_jitterEstimateMode = kMaxEstimate;
|
||||
} else {
|
||||
_maxJitterEstimateMs = kInitialMaxJitterEstimate;
|
||||
_jitterEstimateMode = kLastEstimate;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the current filtered estimate if available,
|
||||
// otherwise tries to calculate an estimate.
|
||||
double
|
||||
int
|
||||
VCMJitterEstimator::GetJitterEstimate(double rttMultiplier)
|
||||
{
|
||||
double jitterMS = CalculateEstimate();
|
||||
double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
|
||||
if (_filterJitterEstimate > jitterMS)
|
||||
{
|
||||
jitterMS = _filterJitterEstimate;
|
||||
}
|
||||
if (_nackCount >= _nackLimit)
|
||||
{
|
||||
return jitterMS + _rttFilter.RttMs() * rttMultiplier;
|
||||
jitterMS += _rttFilter.RttMs() * rttMultiplier;
|
||||
}
|
||||
int jitterMsInt = static_cast<uint32_t>(jitterMS + 0.5);
|
||||
if (_jitterEstimateMode == kLastEstimate) {
|
||||
return jitterMsInt;
|
||||
} else {
|
||||
_maxJitterEstimateMs = VCM_MAX(_maxJitterEstimateMs, jitterMsInt);
|
||||
return _maxJitterEstimateMs;
|
||||
}
|
||||
return jitterMS;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,12 @@
|
||||
namespace webrtc
|
||||
{
|
||||
|
||||
enum VCMJitterEstimateMode
|
||||
{
|
||||
kMaxEstimate,
|
||||
kLastEstimate,
|
||||
};
|
||||
|
||||
class VCMJitterEstimator
|
||||
{
|
||||
public:
|
||||
@ -45,7 +51,7 @@ public:
|
||||
// - rttMultiplier : RTT param multiplier (when applicable).
|
||||
//
|
||||
// Return value : Jitter estimate in milliseconds
|
||||
double GetJitterEstimate(double rttMultiplier);
|
||||
int GetJitterEstimate(double rttMultiplier);
|
||||
|
||||
// Updates the nack counter.
|
||||
void FrameNacked();
|
||||
@ -58,6 +64,11 @@ public:
|
||||
|
||||
void UpdateMaxFrameSize(WebRtc_UWord32 frameSizeBytes);
|
||||
|
||||
// Enable a max filter on the jitter estimate, and setting of the initial
|
||||
// delay (only when in max mode). When disabled (default), the last jitter
|
||||
// estimate will be used.
|
||||
void EnableMaxJitterEstimate(bool enable, uint32_t initial_delay_ms);
|
||||
|
||||
// A constant describing the delay from the jitter buffer
|
||||
// to the delay on the receiving side which is not accounted
|
||||
// for by the jitter buffer nor the decoding delay estimate.
|
||||
@ -144,6 +155,8 @@ private:
|
||||
WebRtc_UWord32 _nackCount; // Keeps track of the number of nacks received,
|
||||
// but never goes above _nackLimit
|
||||
VCMRttFilter _rttFilter;
|
||||
VCMJitterEstimateMode _jitterEstimateMode;
|
||||
int _maxJitterEstimateMs;
|
||||
|
||||
enum { kStartupDelaySamples = 30 };
|
||||
enum { kFsAccuStartupSamples = 5 };
|
||||
|
Loading…
x
Reference in New Issue
Block a user