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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
// accumulate the history.
|
|
||||||
for (; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (_encodedFrameSamples[i]._sizeBytes == -1)
|
|
||||||
{
|
|
||||||
// Found empty slot
|
|
||||||
break;
|
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user