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:
mikhal@webrtc.org 2013-01-31 17:18:02 +00:00
parent e07c661a29
commit 119c67df36
6 changed files with 132 additions and 66 deletions

View File

@ -764,21 +764,23 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(VCMEncodedFrame* encoded_frame,
return ret; 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() { uint32_t VCMJitterBuffer::EstimatedJitterMs() {
CriticalSectionScoped cs(crit_sect_); 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. // low_rtt_nackThresholdMs_ == -1 means no FEC.
double rtt_mult = 1.0f; double rtt_mult = 1.0f;
if (nack_mode_ == kNackHybrid && (low_rtt_nack_threshold_ms_ >= 0 && if (nack_mode_ == kNackHybrid && (low_rtt_nack_threshold_ms_ >= 0 &&
static_cast<int>(rtt_ms_) > low_rtt_nack_threshold_ms_)) { 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; rtt_mult = 0.0f;
} }
estimate += static_cast<uint32_t> return jitter_estimate_.GetJitterEstimate(rtt_mult);
(jitter_estimate_.GetJitterEstimate(rtt_mult) + 0.5);
return estimate;
} }
void VCMJitterBuffer::UpdateRtt(uint32_t rtt_ms) { void VCMJitterBuffer::UpdateRtt(uint32_t rtt_ms) {

View File

@ -13,16 +13,16 @@
#include <list> #include <list>
#include "modules/interface/module_common_types.h" #include "webrtc/modules/interface/module_common_types.h"
#include "modules/video_coding/main/interface/video_coding_defines.h" #include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
#include "modules/video_coding/main/source/decoding_state.h" #include "webrtc/modules/video_coding/main/source/decoding_state.h"
#include "modules/video_coding/main/source/event.h" #include "webrtc/modules/video_coding/main/source/event.h"
#include "modules/video_coding/main/source/inter_frame_delay.h" #include "webrtc/modules/video_coding/main/source/inter_frame_delay.h"
#include "modules/video_coding/main/source/jitter_buffer_common.h" #include "webrtc/modules/video_coding/main/source/jitter_buffer_common.h"
#include "modules/video_coding/main/source/jitter_estimator.h" #include "webrtc/modules/video_coding/main/source/jitter_estimator.h"
#include "system_wrappers/interface/constructor_magic.h" #include "webrtc/system_wrappers/interface/constructor_magic.h"
#include "system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "typedefs.h" #include "webrtc/typedefs.h"
namespace webrtc { namespace webrtc {
@ -124,6 +124,11 @@ class VCMJitterBuffer {
VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame, VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame,
const VCMPacket& packet); 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. // Returns the estimated jitter in milliseconds.
uint32_t EstimatedJitterMs(); uint32_t EstimatedJitterMs();

View File

@ -11,41 +11,36 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_ #ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
#define 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 { kMaxNumberOfFrames = 100 };
enum { kStartNumberOfFrames = 6 }; // in packets, 6 packets are approximately 198 ms, enum { kStartNumberOfFrames = 6 };
// we need at least one more for process enum { kMaxVideoDelayMs = 2000 };
enum { kMaxVideoDelayMs = 2000 }; // in ms
enum VCMJitterBufferEnum enum VCMJitterBufferEnum {
{
kMaxConsecutiveOldFrames = 60, kMaxConsecutiveOldFrames = 60,
kMaxConsecutiveOldPackets = 300, kMaxConsecutiveOldPackets = 300,
kMaxPacketsInSession = 800, kMaxPacketsInSession = 800,
kBufferIncStepSizeBytes = 30000, // >20 packets kBufferIncStepSizeBytes = 30000, // >20 packets.
kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte kMaxJBFrameSizeBytes = 4000000 // sanity don't go above 4Mbyte.
}; };
enum VCMFrameBufferEnum enum VCMFrameBufferEnum {
{
kStateError = -4, kStateError = -4,
kFlushIndicator = -3, // Indicator that a flush has occurred. kFlushIndicator = -3, // Indicator that a flush has occurred.
kTimeStampError = -2, kTimeStampError = -2,
kSizeError = -1, kSizeError = -1,
kNoError = 0, kNoError = 0,
kIncomplete = 1, // Frame incomplete kIncomplete = 1, // Frame incomplete.
kFirstPacket = 2, kFirstPacket = 2,
kCompleteSession = 3, // at least one layer in the frame complete. kCompleteSession = 3, // at least one layer in the frame complete.
kDecodableSession = 4, // Frame incomplete, but ready to be decoded kDecodableSession = 4, // Frame incomplete, but ready to be decoded
kDuplicatePacket = 5 // We're receiving a duplicate packet. kDuplicatePacket = 5 // We're receiving a duplicate packet.
}; };
enum VCMFrameBufferStateEnum enum VCMFrameBufferStateEnum {
{
kStateFree, // Unused frame in the JB kStateFree, // Unused frame in the JB
kStateEmpty, // frame popped by the RTP receiver kStateEmpty, // frame popped by the RTP receiver
kStateIncomplete, // frame that have one or more packet(s) stored kStateIncomplete, // frame that have one or more packet(s) stored
@ -57,12 +52,11 @@ enum VCMFrameBufferStateEnum
enum { kH264StartCodeLengthBytes = 4}; enum { kH264StartCodeLengthBytes = 4};
// Used to indicate if a received packet contain a complete NALU (or equivalent) // Used to indicate if a received packet contain a complete NALU (or equivalent)
enum VCMNaluCompleteness enum VCMNaluCompleteness {
{ kNaluUnset = 0, // Packet has not been filled.
kNaluUnset = 0, //Packet has not been filled. kNaluComplete = 1, // Packet can be decoded as is.
kNaluComplete = 1, //Packet can be decoded as is.
kNaluStart, // Packet contain beginning of NALU kNaluStart, // Packet contain beginning of NALU
kNaluIncomplete, //Packet is not beginning or end of NALU kNaluIncomplete, // Packet is not beginning or end of NALU
kNaluEnd, // Packet is the end of a NALU kNaluEnd, // Packet is the end of a NALU
}; };
@ -78,7 +72,6 @@ WebRtc_UWord32 LatestTimestamp(WebRtc_UWord32 timestamp1,
WebRtc_Word32 LatestSequenceNumber(WebRtc_Word32 seq_num1, WebRtc_Word32 LatestSequenceNumber(WebRtc_Word32 seq_num1,
WebRtc_Word32 seq_num2, WebRtc_Word32 seq_num2,
bool* has_wrapped); bool* has_wrapped);
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_ #endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_

View File

@ -265,6 +265,33 @@ TEST_F(TestRunningJitterBuffer, TestEmptyPackets) {
EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0)); 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) { TEST_F(TestJitterBufferNack, TestEmptyPackets) {
// Make sure empty packets doesn't clog the jitter buffer. // Make sure empty packets doesn't clog the jitter buffer.
jitter_buffer_->SetNackMode(kNackHybrid, kLowRttNackMs, -1); jitter_buffer_->SetNackMode(kNackHybrid, kLowRttNackMs, -1);

View File

@ -20,6 +20,8 @@
namespace webrtc { namespace webrtc {
enum { kInitialMaxJitterEstimate = 0 };
VCMJitterEstimator::VCMJitterEstimator(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId) : VCMJitterEstimator::VCMJitterEstimator(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId) :
_vcmId(vcmId), _vcmId(vcmId),
_receiverId(receiverId), _receiverId(receiverId),
@ -33,7 +35,9 @@ _numStdDevFrameSizeOutlier(3),
_noiseStdDevs(2.33), // ~Less than 1% chance _noiseStdDevs(2.33), // ~Less than 1% chance
// (look up in normal distribution table)... // (look up in normal distribution table)...
_noiseStdDevOffset(30.0), // ...of getting 30 ms freezes _noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
_rttFilter(vcmId, receiverId) _rttFilter(vcmId, receiverId),
_jitterEstimateMode(kLastEstimate),
_maxJitterEstimateMs(kInitialMaxJitterEstimate)
{ {
Reset(); Reset();
} }
@ -62,6 +66,8 @@ VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs)
_startupCount = rhs._startupCount; _startupCount = rhs._startupCount;
_latestNackTimestamp = rhs._latestNackTimestamp; _latestNackTimestamp = rhs._latestNackTimestamp;
_nackCount = rhs._nackCount; _nackCount = rhs._nackCount;
_jitterEstimateMode = rhs._jitterEstimateMode;
_maxJitterEstimateMs = rhs._maxJitterEstimateMs;
_rttFilter = rhs._rttFilter; _rttFilter = rhs._rttFilter;
} }
return *this; return *this;
@ -95,6 +101,8 @@ VCMJitterEstimator::Reset()
_fsSum = 0; _fsSum = 0;
_fsCount = 0; _fsCount = 0;
_startupCount = 0; _startupCount = 0;
_jitterEstimateMode = kLastEstimate;
_maxJitterEstimateMs = kInitialMaxJitterEstimate;
_rttFilter.Reset(); _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, // Returns the current filtered estimate if available,
// otherwise tries to calculate an estimate. // otherwise tries to calculate an estimate.
double int
VCMJitterEstimator::GetJitterEstimate(double rttMultiplier) VCMJitterEstimator::GetJitterEstimate(double rttMultiplier)
{ {
double jitterMS = CalculateEstimate(); double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
if (_filterJitterEstimate > jitterMS) if (_filterJitterEstimate > jitterMS)
{ {
jitterMS = _filterJitterEstimate; jitterMS = _filterJitterEstimate;
} }
if (_nackCount >= _nackLimit) 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;
} }
} }

View File

@ -17,6 +17,12 @@
namespace webrtc namespace webrtc
{ {
enum VCMJitterEstimateMode
{
kMaxEstimate,
kLastEstimate,
};
class VCMJitterEstimator class VCMJitterEstimator
{ {
public: public:
@ -45,7 +51,7 @@ public:
// - rttMultiplier : RTT param multiplier (when applicable). // - rttMultiplier : RTT param multiplier (when applicable).
// //
// Return value : Jitter estimate in milliseconds // Return value : Jitter estimate in milliseconds
double GetJitterEstimate(double rttMultiplier); int GetJitterEstimate(double rttMultiplier);
// Updates the nack counter. // Updates the nack counter.
void FrameNacked(); void FrameNacked();
@ -58,6 +64,11 @@ public:
void UpdateMaxFrameSize(WebRtc_UWord32 frameSizeBytes); 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 // A constant describing the delay from the jitter buffer
// to the delay on the receiving side which is not accounted // to the delay on the receiving side which is not accounted
// for by the jitter buffer nor the decoding delay estimate. // 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, WebRtc_UWord32 _nackCount; // Keeps track of the number of nacks received,
// but never goes above _nackLimit // but never goes above _nackLimit
VCMRttFilter _rttFilter; VCMRttFilter _rttFilter;
VCMJitterEstimateMode _jitterEstimateMode;
int _maxJitterEstimateMs;
enum { kStartupDelaySamples = 30 }; enum { kStartupDelaySamples = 30 };
enum { kFsAccuStartupSamples = 5 }; enum { kFsAccuStartupSamples = 5 };