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:
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user