Fix framerate sent to account for actually sent frames.

TESTS=trybots
BUG=1481

Review URL: https://webrtc-codereview.appspot.com/1195005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3682 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org
2013-03-18 17:04:52 +00:00
parent abc9d5b6aa
commit f4944d49cf
4 changed files with 95 additions and 100 deletions

View File

@@ -221,7 +221,8 @@ VCMEncodedFrameCallback::Encoded(
} }
_encodedBytes = encodedBytes; _encodedBytes = encodedBytes;
if (_mediaOpt != NULL) { if (_mediaOpt != NULL) {
_mediaOpt->UpdateWithEncodedData(_encodedBytes, frameType); _mediaOpt->UpdateWithEncodedData(_encodedBytes, encodedImage._timeStamp,
frameType);
if (_internalSource) if (_internalSource)
{ {
return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame

View File

@@ -36,7 +36,8 @@ _enableQm(false),
_videoProtectionCallback(NULL), _videoProtectionCallback(NULL),
_videoQMSettingsCallback(NULL), _videoQMSettingsCallback(NULL),
_encodedFrameSamples(), _encodedFrameSamples(),
_avgSentBitRateBps(0.0f), _avgSentBitRateBps(0),
_avgSentFramerate(0),
_keyFrameCnt(0), _keyFrameCnt(0),
_deltaFrameCnt(0), _deltaFrameCnt(0),
_lastQMUpdateTime(0), _lastQMUpdateTime(0),
@@ -82,12 +83,8 @@ VCMMediaOptimization::Reset()
_deltaFrameCnt = 0; _deltaFrameCnt = 0;
_lastQMUpdateTime = 0; _lastQMUpdateTime = 0;
_lastChangeTime = 0; _lastChangeTime = 0;
for (WebRtc_Word32 i = 0; i < kBitrateMaxFrameSamples; i++) _encodedFrameSamples.clear();
{ _avgSentBitRateBps = 0;
_encodedFrameSamples[i]._sizeBytes = -1;
_encodedFrameSamples[i]._timeCompleteMs = -1;
}
_avgSentBitRateBps = 0.0f;
_numLayers = 1; _numLayers = 1;
return VCM_OK; return VCM_OK;
} }
@@ -187,7 +184,7 @@ VCMMediaOptimization::SetTargetRates(WebRtc_UWord32 target_bitrate,
_qmResolution->UpdateRates(target_bitrate_kbps, sent_video_rate_kbps, _qmResolution->UpdateRates(target_bitrate_kbps, sent_video_rate_kbps,
_incomingFrameRate, _fractionLost); _incomingFrameRate, _fractionLost);
// Check for QM selection // Check for QM selection
bool selectQM = checkStatusForQMchange(); bool selectQM = CheckStatusForQMchange();
if (selectQM) if (selectQM)
{ {
SelectQuality(); SelectQuality();
@@ -346,22 +343,20 @@ VCMMediaOptimization::SetMtu(WebRtc_Word32 mtu)
_maxPayloadSize = mtu; _maxPayloadSize = mtu;
} }
float uint32_t
VCMMediaOptimization::SentFrameRate() VCMMediaOptimization::SentFrameRate()
{ {
if (_frameDropper) PurgeOldFrameSamples(_clock->TimeInMilliseconds());
{ UpdateSentFramerate();
return _frameDropper->ActualFrameRate((WebRtc_UWord32)(InputFrameRate() return _avgSentFramerate;
+ 0.5f));
}
return VCM_CODEC_ERROR;
} }
float uint32_t
VCMMediaOptimization::SentBitRate() VCMMediaOptimization::SentBitRate()
{ {
UpdateBitRateEstimate(-1, _clock->TimeInMilliseconds()); const int64_t now_ms = _clock->TimeInMilliseconds();
PurgeOldFrameSamples(now_ms);
UpdateSentBitrate(now_ms);
return _avgSentBitRateBps; return _avgSentBitRateBps;
} }
@@ -372,11 +367,16 @@ VCMMediaOptimization::MaxBitRate()
} }
WebRtc_Word32 WebRtc_Word32
VCMMediaOptimization::UpdateWithEncodedData(WebRtc_Word32 encodedLength, VCMMediaOptimization::UpdateWithEncodedData(int encodedLength,
uint32_t timestamp,
FrameType encodedFrameType) FrameType encodedFrameType)
{ {
// look into the ViE version - debug mode - needs also number of layers. const int64_t now_ms = _clock->TimeInMilliseconds();
UpdateBitRateEstimate(encodedLength, _clock->TimeInMilliseconds()); PurgeOldFrameSamples(now_ms);
_encodedFrameSamples.push_back(VCMEncodedFrameSample(
encodedLength, timestamp, now_ms));
UpdateSentBitrate(now_ms);
UpdateSentFramerate();
if(encodedLength > 0) if(encodedLength > 0)
{ {
const bool deltaFrame = (encodedFrameType != kVideoFrameKey && const bool deltaFrame = (encodedFrameType != kVideoFrameKey &&
@@ -426,67 +426,51 @@ VCMMediaOptimization::UpdateWithEncodedData(WebRtc_Word32 encodedLength,
} }
void VCMMediaOptimization::UpdateBitRateEstimate(WebRtc_Word64 encodedLength, void VCMMediaOptimization::PurgeOldFrameSamples(int64_t now_ms) {
WebRtc_Word64 nowMs) while (!_encodedFrameSamples.empty()) {
{ if (now_ms - _encodedFrameSamples.front().time_complete_ms >
int i = kBitrateMaxFrameSamples - 1; kBitrateAverageWinMs) {
WebRtc_UWord32 frameSizeSum = 0; _encodedFrameSamples.pop_front();
WebRtc_Word64 timeOldest = -1; } else {
// Find an empty slot for storing the new sample and at the same time break;
// accumulate the history.
for (; i >= 0; i--)
{
if (_encodedFrameSamples[i]._sizeBytes == -1)
{
// Found empty slot
break;
}
if (nowMs - _encodedFrameSamples[i]._timeCompleteMs <
kBitrateAverageWinMs)
{
frameSizeSum += static_cast<WebRtc_UWord32>
(_encodedFrameSamples[i]._sizeBytes);
if (timeOldest == -1)
{
timeOldest = _encodedFrameSamples[i]._timeCompleteMs;
}
}
}
if (encodedLength > 0)
{
if (i < 0)
{
// No empty slot, shift
for (i = kBitrateMaxFrameSamples - 2; i >= 0; i--)
{
_encodedFrameSamples[i + 1] = _encodedFrameSamples[i];
}
i++;
}
// Insert new sample
_encodedFrameSamples[i]._sizeBytes = encodedLength;
_encodedFrameSamples[i]._timeCompleteMs = nowMs;
}
if (timeOldest > -1)
{
// Update average bit rate
float denom = static_cast<float>(nowMs - timeOldest);
if (denom < 1.0)
{
denom = 1.0;
}
_avgSentBitRateBps = (frameSizeSum + encodedLength) * 8 * 1000 / denom;
}
else if (encodedLength > 0)
{
_avgSentBitRateBps = static_cast<float>(encodedLength * 8);
}
else
{
_avgSentBitRateBps = 0;
} }
}
} }
void VCMMediaOptimization::UpdateSentBitrate(int64_t now_ms) {
if (_encodedFrameSamples.empty()) {
_avgSentBitRateBps = 0;
return;
}
int framesize_sum = 0;
for (FrameSampleList::iterator it = _encodedFrameSamples.begin();
it != _encodedFrameSamples.end(); ++it) {
framesize_sum += it->size_bytes;
}
float denom = static_cast<float>(
now_ms - _encodedFrameSamples.back().time_complete_ms);
if (denom >= 1.0f) {
_avgSentBitRateBps = static_cast<uint32_t>(framesize_sum * 8 * 1000 /
denom + 0.5f);
} else {
_avgSentBitRateBps = framesize_sum * 8;
}
}
void VCMMediaOptimization::UpdateSentFramerate() {
if (_encodedFrameSamples.size() <= 1) {
_avgSentFramerate = _encodedFrameSamples.size();
return;
}
int denom = _encodedFrameSamples.back().timestamp -
_encodedFrameSamples.front().timestamp;
if (denom > 0) {
_avgSentFramerate = (90000 * (_encodedFrameSamples.size() - 1) + denom / 2)
/ denom;
} else {
_avgSentFramerate = _encodedFrameSamples.size();
}
}
WebRtc_Word32 WebRtc_Word32
VCMMediaOptimization::RegisterVideoQMCallback(VCMQMSettingsCallback* VCMMediaOptimization::RegisterVideoQMCallback(VCMQMSettingsCallback*
@@ -506,7 +490,7 @@ VCMMediaOptimization::RegisterVideoQMCallback(VCMQMSettingsCallback*
} }
void void
VCMMediaOptimization::updateContentData(const VideoContentMetrics* VCMMediaOptimization::UpdateContentData(const VideoContentMetrics*
contentMetrics) contentMetrics)
{ {
// Updating content metrics // Updating content metrics
@@ -560,7 +544,7 @@ VCMMediaOptimization::SelectQuality()
// (2) target bit rate // (2) target bit rate
bool bool
VCMMediaOptimization::checkStatusForQMchange() VCMMediaOptimization::CheckStatusForQMchange()
{ {
bool status = true; bool status = true;

View File

@@ -17,6 +17,8 @@
#include "media_opt_util.h" #include "media_opt_util.h"
#include "qm_select.h" #include "qm_select.h"
#include <list>
namespace webrtc { namespace webrtc {
class Clock; class Clock;
@@ -28,12 +30,16 @@ namespace media_optimization {
enum { kBitrateMaxFrameSamples = 60 }; enum { kBitrateMaxFrameSamples = 60 };
enum { kBitrateAverageWinMs = 1000 }; enum { kBitrateAverageWinMs = 1000 };
struct VCMEncodedFrameSample struct VCMEncodedFrameSample {
{ VCMEncodedFrameSample(int size_bytes, uint32_t timestamp,
VCMEncodedFrameSample() : _sizeBytes(-1), _timeCompleteMs(-1) {} int64_t time_complete_ms)
: size_bytes(size_bytes),
timestamp(timestamp),
time_complete_ms(time_complete_ms) {}
WebRtc_Word64 _sizeBytes; uint32_t size_bytes;
WebRtc_Word64 _timeCompleteMs; uint32_t timestamp;
int64_t time_complete_ms;
}; };
class VCMMediaOptimization class VCMMediaOptimization
@@ -87,11 +93,11 @@ public:
/* /*
* Get actual sent frame rate * Get actual sent frame rate
*/ */
float SentFrameRate(); uint32_t SentFrameRate();
/* /*
* Get actual sent bit rate * Get actual sent bit rate
*/ */
float SentBitRate(); uint32_t SentBitRate();
/* /*
* Get maximum allowed bit rate * Get maximum allowed bit rate
*/ */
@@ -99,7 +105,8 @@ public:
/* /*
* Inform Media Optimization of encoding output: Length and frame type * Inform Media Optimization of encoding output: Length and frame type
*/ */
WebRtc_Word32 UpdateWithEncodedData(WebRtc_Word32 encodedLength, WebRtc_Word32 UpdateWithEncodedData(int encodedLength,
uint32_t timestamp,
FrameType encodedFrameType); FrameType encodedFrameType);
/* /*
* Register a protection callback to be used to inform the user about the * Register a protection callback to be used to inform the user about the
@@ -128,7 +135,7 @@ public:
/** /**
* Update content metric Data * Update content metric Data
*/ */
void updateContentData(const VideoContentMetrics* contentMetrics); void UpdateContentData(const VideoContentMetrics* contentMetrics);
/** /**
* Compute new Quality Mode * Compute new Quality Mode
@@ -136,6 +143,7 @@ public:
WebRtc_Word32 SelectQuality(); WebRtc_Word32 SelectQuality();
private: private:
typedef std::list<VCMEncodedFrameSample> FrameSampleList;
/* /*
* Update protection callback with protection settings * Update protection callback with protection settings
@@ -145,7 +153,10 @@ private:
uint32_t* nack_overhead_rate_bps, uint32_t* nack_overhead_rate_bps,
uint32_t* fec_overhead_rate_bps); uint32_t* fec_overhead_rate_bps);
void UpdateBitRateEstimate(WebRtc_Word64 encodedLength, WebRtc_Word64 nowMs); void PurgeOldFrameSamples(int64_t now_ms);
void UpdateSentBitrate(int64_t nowMs);
void UpdateSentFramerate();
/* /*
* verify if QM settings differ from default, i.e. if an update is required * verify if QM settings differ from default, i.e. if an update is required
* Compute actual values, as will be sent to the encoder * Compute actual values, as will be sent to the encoder
@@ -155,7 +166,7 @@ private:
* check if we should make a QM change * check if we should make a QM change
* will return 1 if yes, 0 otherwise * will return 1 if yes, 0 otherwise
*/ */
bool checkStatusForQMchange(); bool CheckStatusForQMchange();
void ProcessIncomingFrameRate(WebRtc_Word64 now); void ProcessIncomingFrameRate(WebRtc_Word64 now);
@@ -188,8 +199,9 @@ private:
VCMProtectionCallback* _videoProtectionCallback; VCMProtectionCallback* _videoProtectionCallback;
VCMQMSettingsCallback* _videoQMSettingsCallback; VCMQMSettingsCallback* _videoQMSettingsCallback;
VCMEncodedFrameSample _encodedFrameSamples[kBitrateMaxFrameSamples]; std::list<VCMEncodedFrameSample> _encodedFrameSamples;
float _avgSentBitRateBps; uint32_t _avgSentBitRateBps;
uint32_t _avgSentFramerate;
WebRtc_UWord32 _keyFrameCnt; WebRtc_UWord32 _keyFrameCnt;
WebRtc_UWord32 _deltaFrameCnt; WebRtc_UWord32 _deltaFrameCnt;

View File

@@ -167,10 +167,8 @@ VideoCodingModuleImpl::Process()
WebRtc_UWord32 frameRate; WebRtc_UWord32 frameRate;
{ {
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
bitRate = static_cast<WebRtc_UWord32>( bitRate = _mediaOpt.SentBitRate();
_mediaOpt.SentBitRate() + 0.5f); frameRate = _mediaOpt.SentFrameRate();
frameRate = static_cast<WebRtc_UWord32>(
_mediaOpt.SentFrameRate() + 0.5f);
} }
_sendStatsCallback->SendStatistics(bitRate, frameRate); _sendStatsCallback->SendStatistics(bitRate, frameRate);
} }
@@ -700,7 +698,7 @@ VideoCodingModuleImpl::AddVideoFrame(const I420VideoFrame& videoFrame,
} }
else else
{ {
_mediaOpt.updateContentData(contentMetrics); _mediaOpt.UpdateContentData(contentMetrics);
WebRtc_Word32 ret = _encoder->Encode(videoFrame, WebRtc_Word32 ret = _encoder->Encode(videoFrame,
codecSpecificInfo, codecSpecificInfo,
_nextFrameTypes); _nextFrameTypes);