Remove sent framerate and bitrate calculations from MediaOptimization.

Add RateTracker for sent framerate and bitrate in SendStatisticsProxy.

Store sent frame info in map to solve potential issue where sent framerate statistics could be
incorrect.

Bug: webrtc:8375
Change-Id: I4a6e3956013438a711b8c2e73a8cd90c52dd1210
Reviewed-on: https://webrtc-review.googlesource.com/7880
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20225}
This commit is contained in:
Åsa Persson
2017-10-10 16:19:37 +02:00
committed by Commit Bot
parent 245660a33d
commit af721b72cc
8 changed files with 120 additions and 171 deletions

View File

@ -13,26 +13,10 @@
#include <limits>
#include "modules/video_coding/utility/frame_dropper.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"
namespace webrtc {
namespace media_optimization {
const int kMsPerSec = 1000;
const int kBitsPerByte = 8;
struct MediaOptimization::EncodedFrameSample {
EncodedFrameSample(size_t size_bytes,
uint32_t timestamp,
int64_t time_complete_ms)
: size_bytes(size_bytes),
timestamp(timestamp),
time_complete_ms(time_complete_ms) {}
size_t size_bytes;
uint32_t timestamp;
int64_t time_complete_ms;
};
MediaOptimization::MediaOptimization(Clock* clock)
: clock_(clock),
@ -40,9 +24,7 @@ MediaOptimization::MediaOptimization(Clock* clock)
user_frame_rate_(0),
frame_dropper_(new FrameDropper),
video_target_bitrate_(0),
incoming_frame_rate_(0),
encoded_frame_samples_(),
avg_sent_framerate_(0) {
incoming_frame_rate_(0) {
memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
}
@ -58,7 +40,6 @@ void MediaOptimization::Reset() {
frame_dropper_->SetRates(0, 0);
video_target_bitrate_ = 0;
user_frame_rate_ = 0;
encoded_frame_samples_.clear();
}
void MediaOptimization::SetEncodingData(int32_t max_bit_rate,
@ -117,51 +98,14 @@ uint32_t MediaOptimization::InputFrameRateInternal() {
return framerate;
}
uint32_t MediaOptimization::SentFrameRate() {
rtc::CritScope lock(&crit_sect_);
return SentFrameRateInternal();
}
uint32_t MediaOptimization::SentFrameRateInternal() {
PurgeOldFrameSamples(clock_->TimeInMilliseconds() - kBitrateAverageWinMs);
UpdateSentFramerate();
return avg_sent_framerate_;
}
uint32_t MediaOptimization::SentBitRate() {
rtc::CritScope lock(&crit_sect_);
PurgeOldFrameSamples(clock_->TimeInMilliseconds() - kBitrateAverageWinMs);
size_t sent_bytes = 0;
for (auto& frame_sample : encoded_frame_samples_) {
sent_bytes += frame_sample.size_bytes;
}
return sent_bytes * kBitsPerByte * kMsPerSec / kBitrateAverageWinMs;
}
int32_t MediaOptimization::UpdateWithEncodedData(
const EncodedImage& encoded_image) {
size_t encoded_length = encoded_image._length;
uint32_t timestamp = encoded_image._timeStamp;
rtc::CritScope lock(&crit_sect_);
const int64_t now_ms = clock_->TimeInMilliseconds();
PurgeOldFrameSamples(now_ms - kBitrateAverageWinMs);
if (encoded_frame_samples_.size() > 0 &&
encoded_frame_samples_.back().timestamp == timestamp) {
// Frames having the same timestamp are generated from the same input
// frame. We don't want to double count them, but only increment the
// size_bytes.
encoded_frame_samples_.back().size_bytes += encoded_length;
encoded_frame_samples_.back().time_complete_ms = now_ms;
} else {
encoded_frame_samples_.push_back(
EncodedFrameSample(encoded_length, timestamp, now_ms));
}
UpdateSentFramerate();
if (encoded_length > 0) {
const bool delta_frame = encoded_image._frameType != kVideoFrameKey;
frame_dropper_->Fill(encoded_length, delta_frame);
}
return VCM_OK;
}
@ -192,31 +136,6 @@ void MediaOptimization::UpdateIncomingFrameRate() {
ProcessIncomingFrameRate(now);
}
void MediaOptimization::PurgeOldFrameSamples(int64_t threshold_ms) {
while (!encoded_frame_samples_.empty()) {
if (encoded_frame_samples_.front().time_complete_ms < threshold_ms) {
encoded_frame_samples_.pop_front();
} else {
break;
}
}
}
void MediaOptimization::UpdateSentFramerate() {
if (encoded_frame_samples_.size() <= 1) {
avg_sent_framerate_ = encoded_frame_samples_.size();
return;
}
int denom = encoded_frame_samples_.back().timestamp -
encoded_frame_samples_.front().timestamp;
if (denom > 0) {
avg_sent_framerate_ =
(90000 * (encoded_frame_samples_.size() - 1) + denom / 2) / denom;
} else {
avg_sent_framerate_ = encoded_frame_samples_.size();
}
}
// Allowing VCM to keep track of incoming frame rate.
void MediaOptimization::ProcessIncomingFrameRate(int64_t now) {
int32_t num = 0;

View File

@ -57,22 +57,12 @@ class MediaOptimization {
// InputFrameRate 0 = no frame rate estimate available.
uint32_t InputFrameRate();
uint32_t SentFrameRate();
uint32_t SentBitRate();
private:
enum { kFrameCountHistorySize = 90 };
enum { kFrameHistoryWinMs = 2000 };
enum { kBitrateAverageWinMs = 1000 };
struct EncodedFrameSample;
typedef std::list<EncodedFrameSample> FrameSampleList;
void UpdateIncomingFrameRate() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
void PurgeOldFrameSamples(int64_t threshold_ms)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
void UpdateSentFramerate() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
void ProcessIncomingFrameRate(int64_t now)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
@ -88,8 +78,6 @@ class MediaOptimization {
uint32_t InputFrameRateInternal() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
uint32_t SentFrameRateInternal() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
// Protect all members.
rtc::CriticalSection crit_sect_;
@ -101,9 +89,6 @@ class MediaOptimization {
float incoming_frame_rate_ RTC_GUARDED_BY(crit_sect_);
int64_t incoming_frame_times_[kFrameCountHistorySize] RTC_GUARDED_BY(
crit_sect_);
std::list<EncodedFrameSample> encoded_frame_samples_
RTC_GUARDED_BY(crit_sect_);
uint32_t avg_sent_framerate_ RTC_GUARDED_BY(crit_sect_);
};
} // namespace media_optimization
} // namespace webrtc

View File

@ -52,14 +52,15 @@ VideoSender::VideoSender(Clock* clock,
VideoSender::~VideoSender() {}
// TODO(asapersson): Remove _sendStatsTimer and send_stats_callback_.
void VideoSender::Process() {
if (_sendStatsTimer.TimeUntilProcess() == 0) {
// |_sendStatsTimer.Processed()| must be called. Otherwise
// VideoSender::Process() will be called in an infinite loop.
_sendStatsTimer.Processed();
if (send_stats_callback_) {
uint32_t bitRate = _mediaOpt.SentBitRate();
uint32_t frameRate = _mediaOpt.SentFrameRate();
uint32_t bitRate = 0;
uint32_t frameRate = 0;
send_stats_callback_->SendStatistics(bitRate, frameRate);
}
}