Add stats for video:
- number of sent/received RTCP NACK/FIR/PLI per minute - percentage of unique sent/received NACK requests - percentage of discarded/duplicated packets by the jitter buffer - permille of sent/received key frames BUG=crbug/419657 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/24959004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7592 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
2236267b5e
commit
96dc685143
@ -25,6 +25,7 @@
|
||||
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/metrics.h"
|
||||
#include "webrtc/system_wrappers/interface/trace_event.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -143,6 +144,8 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock, EventFactory* event_factory)
|
||||
drop_count_(0),
|
||||
num_consecutive_old_frames_(0),
|
||||
num_consecutive_old_packets_(0),
|
||||
num_packets_(0),
|
||||
num_duplicated_packets_(0),
|
||||
num_discarded_packets_(0),
|
||||
jitter_estimate_(clock),
|
||||
inter_frame_delay_(clock_->TimeInMilliseconds()),
|
||||
@ -190,6 +193,8 @@ void VCMJitterBuffer::CopyFrom(const VCMJitterBuffer& rhs) {
|
||||
drop_count_ = rhs.drop_count_;
|
||||
num_consecutive_old_frames_ = rhs.num_consecutive_old_frames_;
|
||||
num_consecutive_old_packets_ = rhs.num_consecutive_old_packets_;
|
||||
num_packets_ = rhs.num_packets_;
|
||||
num_duplicated_packets_ = rhs.num_duplicated_packets_;
|
||||
num_discarded_packets_ = rhs.num_discarded_packets_;
|
||||
jitter_estimate_ = rhs.jitter_estimate_;
|
||||
inter_frame_delay_ = rhs.inter_frame_delay_;
|
||||
@ -238,6 +243,15 @@ void VCMJitterBuffer::CopyFrames(FrameList* to_list,
|
||||
}
|
||||
}
|
||||
|
||||
void VCMJitterBuffer::UpdateHistograms() {
|
||||
if (num_packets_ > 0) {
|
||||
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DiscardedPacketsInPercent",
|
||||
num_discarded_packets_ * 100 / num_packets_);
|
||||
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DuplicatedPacketsInPercent",
|
||||
num_duplicated_packets_ * 100 / num_packets_);
|
||||
}
|
||||
}
|
||||
|
||||
void VCMJitterBuffer::Start() {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
running_ = true;
|
||||
@ -250,6 +264,8 @@ void VCMJitterBuffer::Start() {
|
||||
|
||||
num_consecutive_old_frames_ = 0;
|
||||
num_consecutive_old_packets_ = 0;
|
||||
num_packets_ = 0;
|
||||
num_duplicated_packets_ = 0;
|
||||
num_discarded_packets_ = 0;
|
||||
|
||||
// Start in a non-signaled state.
|
||||
@ -265,6 +281,7 @@ void VCMJitterBuffer::Start() {
|
||||
|
||||
void VCMJitterBuffer::Stop() {
|
||||
crit_sect_->Enter();
|
||||
UpdateHistograms();
|
||||
running_ = false;
|
||||
last_decoded_state_.Reset();
|
||||
free_frames_.clear();
|
||||
@ -313,6 +330,16 @@ std::map<FrameType, uint32_t> VCMJitterBuffer::FrameStatistics() const {
|
||||
return receive_statistics_;
|
||||
}
|
||||
|
||||
int VCMJitterBuffer::num_packets() const {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
return num_packets_;
|
||||
}
|
||||
|
||||
int VCMJitterBuffer::num_duplicated_packets() const {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
return num_duplicated_packets_;
|
||||
}
|
||||
|
||||
int VCMJitterBuffer::num_discarded_packets() const {
|
||||
CriticalSectionScoped cs(crit_sect_);
|
||||
return num_discarded_packets_;
|
||||
@ -543,6 +570,7 @@ void VCMJitterBuffer::ReleaseFrame(VCMEncodedFrame* frame) {
|
||||
// Gets frame to use for this timestamp. If no match, get empty frame.
|
||||
VCMFrameBufferEnum VCMJitterBuffer::GetFrame(const VCMPacket& packet,
|
||||
VCMFrameBuffer** frame) {
|
||||
++num_packets_;
|
||||
// Does this packet belong to an old frame?
|
||||
if (last_decoded_state_.IsOldPacket(&packet)) {
|
||||
// Account only for media packets.
|
||||
@ -747,6 +775,7 @@ VCMFrameBufferEnum VCMJitterBuffer::InsertPacket(const VCMPacket& packet,
|
||||
case kNoError:
|
||||
case kOutOfBoundsPacket:
|
||||
case kDuplicatePacket: {
|
||||
++num_duplicated_packets_;
|
||||
break;
|
||||
}
|
||||
case kFlushIndicator:
|
||||
|
@ -103,6 +103,12 @@ class VCMJitterBuffer {
|
||||
// won't be able to decode them.
|
||||
int num_not_decodable_packets() const;
|
||||
|
||||
// Gets number of packets received.
|
||||
int num_packets() const;
|
||||
|
||||
// Gets number of duplicated packets received.
|
||||
int num_duplicated_packets() const;
|
||||
|
||||
// Gets number of packets discarded by the jitter buffer.
|
||||
int num_discarded_packets() const;
|
||||
|
||||
@ -271,6 +277,8 @@ class VCMJitterBuffer {
|
||||
|
||||
uint16_t EstimatedLowSequenceNumber(const VCMFrameBuffer& frame) const;
|
||||
|
||||
void UpdateHistograms();
|
||||
|
||||
Clock* clock_;
|
||||
// If we are running (have started) or not.
|
||||
bool running_;
|
||||
@ -303,6 +311,10 @@ class VCMJitterBuffer {
|
||||
int num_consecutive_old_frames_;
|
||||
// Number of packets in a row that have been too old.
|
||||
int num_consecutive_old_packets_;
|
||||
// Number of packets received.
|
||||
int num_packets_;
|
||||
// Number of duplicated packets received.
|
||||
int num_duplicated_packets_;
|
||||
// Number of packets discarded by the jitter buffer.
|
||||
int num_discarded_packets_;
|
||||
|
||||
|
@ -512,6 +512,8 @@ TEST_F(TestBasicJitterBuffer, DuplicatePackets) {
|
||||
packet_->markerBit = false;
|
||||
packet_->seqNum = seq_num_;
|
||||
packet_->timestamp = timestamp_;
|
||||
EXPECT_EQ(0, jitter_buffer_->num_packets());
|
||||
EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets());
|
||||
|
||||
bool retransmitted = false;
|
||||
EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(*packet_,
|
||||
@ -520,6 +522,8 @@ TEST_F(TestBasicJitterBuffer, DuplicatePackets) {
|
||||
VCMEncodedFrame* frame_out = DecodeCompleteFrame();
|
||||
|
||||
EXPECT_TRUE(frame_out == NULL);
|
||||
EXPECT_EQ(1, jitter_buffer_->num_packets());
|
||||
EXPECT_EQ(0, jitter_buffer_->num_duplicated_packets());
|
||||
|
||||
packet_->isFirstPacket = false;
|
||||
packet_->markerBit = true;
|
||||
@ -527,6 +531,8 @@ TEST_F(TestBasicJitterBuffer, DuplicatePackets) {
|
||||
// Insert a packet into a frame.
|
||||
EXPECT_EQ(kDuplicatePacket, jitter_buffer_->InsertPacket(*packet_,
|
||||
&retransmitted));
|
||||
EXPECT_EQ(2, jitter_buffer_->num_packets());
|
||||
EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets());
|
||||
|
||||
seq_num_++;
|
||||
packet_->seqNum = seq_num_;
|
||||
@ -539,6 +545,8 @@ TEST_F(TestBasicJitterBuffer, DuplicatePackets) {
|
||||
CheckOutFrame(frame_out, 2 * size_, false);
|
||||
|
||||
EXPECT_EQ(kVideoFrameKey, frame_out->FrameType());
|
||||
EXPECT_EQ(3, jitter_buffer_->num_packets());
|
||||
EXPECT_EQ(1, jitter_buffer_->num_duplicated_packets());
|
||||
}
|
||||
|
||||
TEST_F(TestBasicJitterBuffer, H264InsertStartCode) {
|
||||
|
@ -69,12 +69,26 @@
|
||||
// Also consider changing string to const char* when switching to atomics.
|
||||
|
||||
// Histogram for counters.
|
||||
#define RTC_HISTOGRAM_COUNTS_100(name, sample) RTC_HISTOGRAM_COUNTS( \
|
||||
name, sample, 1, 100, 50)
|
||||
|
||||
#define RTC_HISTOGRAM_COUNTS_1000(name, sample) RTC_HISTOGRAM_COUNTS( \
|
||||
name, sample, 1, 1000, 50)
|
||||
|
||||
#define RTC_HISTOGRAM_COUNTS_10000(name, sample) RTC_HISTOGRAM_COUNTS( \
|
||||
name, sample, 1, 10000, 50)
|
||||
|
||||
#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
|
||||
RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
|
||||
webrtc::metrics::HistogramFactoryGetCounts( \
|
||||
name, min, max, bucket_count))
|
||||
|
||||
// Histogram for percentage.
|
||||
#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
|
||||
RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
|
||||
|
||||
// Histogram for enumerators.
|
||||
// |boundary| should be above the max enumerator sample.
|
||||
#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
|
||||
RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
|
||||
webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "webrtc/modules/video_render/include/video_render_defines.h"
|
||||
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/metrics.h"
|
||||
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
|
||||
#include "webrtc/video_engine/call_stats.h"
|
||||
#include "webrtc/video_engine/include/vie_codec.h"
|
||||
@ -147,7 +148,8 @@ ViEChannel::ViEChannel(int32_t channel_id,
|
||||
sender_(sender),
|
||||
nack_history_size_sender_(kSendSidePacketHistorySize),
|
||||
max_nack_reordering_threshold_(kMaxPacketAgeToNack),
|
||||
pre_render_callback_(NULL) {
|
||||
pre_render_callback_(NULL),
|
||||
start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()) {
|
||||
RtpRtcp::Configuration configuration;
|
||||
configuration.id = ViEModuleId(engine_id, channel_id);
|
||||
configuration.audio = false;
|
||||
@ -222,6 +224,7 @@ int32_t ViEChannel::Init() {
|
||||
}
|
||||
|
||||
ViEChannel::~ViEChannel() {
|
||||
UpdateHistograms();
|
||||
// Make sure we don't get more callbacks from the RTP module.
|
||||
module_process_thread_.DeRegisterModule(vie_receiver_.GetReceiveStatistics());
|
||||
module_process_thread_.DeRegisterModule(rtp_rtcp_.get());
|
||||
@ -246,6 +249,55 @@ ViEChannel::~ViEChannel() {
|
||||
VideoCodingModule::Destroy(vcm_);
|
||||
}
|
||||
|
||||
void ViEChannel::UpdateHistograms() {
|
||||
const float kMinCallLengthInMinutes = 0.5f;
|
||||
float elapsed_minutes =
|
||||
(Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_) / 60000.0f;
|
||||
if (elapsed_minutes < kMinCallLengthInMinutes) {
|
||||
return;
|
||||
}
|
||||
RtcpPacketTypeCounter rtcp_sent;
|
||||
RtcpPacketTypeCounter rtcp_received;
|
||||
GetRtcpPacketTypeCounters(&rtcp_sent, &rtcp_received);
|
||||
|
||||
if (sender_) {
|
||||
if (rtcp_received.nack_requests > 0) {
|
||||
RTC_HISTOGRAM_PERCENTAGE(
|
||||
"WebRTC.Video.UniqueNackRequestsReceivedInPercent",
|
||||
rtcp_received.UniqueNackRequestsInPercent());
|
||||
}
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsReceivedPerMinute",
|
||||
rtcp_received.nack_packets / elapsed_minutes);
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsReceivedPerMinute",
|
||||
rtcp_received.fir_packets / elapsed_minutes);
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsReceivedPerMinute",
|
||||
rtcp_received.pli_packets / elapsed_minutes);
|
||||
} else if (vie_receiver_.GetRemoteSsrc() > 0) {
|
||||
// Get receive stats if we are receiving packets, i.e. there is a remote
|
||||
// ssrc.
|
||||
if (rtcp_sent.nack_requests > 0) {
|
||||
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
|
||||
rtcp_sent.UniqueNackRequestsInPercent());
|
||||
}
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
|
||||
rtcp_sent.nack_packets / elapsed_minutes);
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
|
||||
rtcp_sent.fir_packets / elapsed_minutes);
|
||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
|
||||
rtcp_sent.pli_packets / elapsed_minutes);
|
||||
|
||||
webrtc::VCMFrameCount frames;
|
||||
if (vcm_->ReceivedFrameCount(frames) == VCM_OK) {
|
||||
uint32_t total_frames = frames.numKeyFrames + frames.numDeltaFrames;
|
||||
if (total_frames > 0) {
|
||||
RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille",
|
||||
static_cast<int>((frames.numKeyFrames * 1000.0f / total_frames) +
|
||||
0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
|
||||
bool new_stream) {
|
||||
if (!sender_) {
|
||||
|
@ -383,6 +383,8 @@ class ViEChannel
|
||||
int GetRequiredNackListSize(int target_delay_ms);
|
||||
void SetRtxSendStatus(bool enable);
|
||||
|
||||
void UpdateHistograms();
|
||||
|
||||
// ViEChannel exposes methods that allow to modify observers and callbacks
|
||||
// to be modified. Such an API-style is cumbersome to implement and maintain
|
||||
// at all the levels when comparing to only setting them at construction. As
|
||||
@ -499,6 +501,7 @@ class ViEChannel
|
||||
int nack_history_size_sender_;
|
||||
int max_nack_reordering_threshold_;
|
||||
I420FrameCallback* pre_render_callback_;
|
||||
const int64_t start_ms_;
|
||||
|
||||
std::map<uint32_t, RTCPReportBlock> prev_report_blocks_;
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/metrics.h"
|
||||
#include "webrtc/system_wrappers/interface/tick_util.h"
|
||||
#include "webrtc/system_wrappers/interface/trace_event.h"
|
||||
#include "webrtc/video_engine/include/vie_codec.h"
|
||||
@ -156,7 +157,8 @@ ViEEncoder::ViEEncoder(int32_t engine_id,
|
||||
picture_id_rpsi_(0),
|
||||
qm_callback_(NULL),
|
||||
video_suspended_(false),
|
||||
pre_encode_callback_(NULL) {
|
||||
pre_encode_callback_(NULL),
|
||||
start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()) {
|
||||
RtpRtcp::Configuration configuration;
|
||||
configuration.id = ViEModuleId(engine_id_, channel_id_);
|
||||
configuration.audio = false; // Video.
|
||||
@ -225,6 +227,7 @@ bool ViEEncoder::Init() {
|
||||
}
|
||||
|
||||
ViEEncoder::~ViEEncoder() {
|
||||
UpdateHistograms();
|
||||
if (bitrate_controller_) {
|
||||
bitrate_controller_->RemoveBitrateObserver(bitrate_observer_.get());
|
||||
}
|
||||
@ -237,6 +240,25 @@ ViEEncoder::~ViEEncoder() {
|
||||
delete qm_callback_;
|
||||
}
|
||||
|
||||
void ViEEncoder::UpdateHistograms() {
|
||||
const float kMinCallLengthInMinutes = 0.5f;
|
||||
float elapsed_minutes =
|
||||
(Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_) / 60000.0f;
|
||||
if (elapsed_minutes < kMinCallLengthInMinutes) {
|
||||
return;
|
||||
}
|
||||
webrtc::VCMFrameCount frames;
|
||||
if (vcm_.SentFrameCount(frames) != VCM_OK) {
|
||||
return;
|
||||
}
|
||||
uint32_t total_frames = frames.numKeyFrames + frames.numDeltaFrames;
|
||||
if (total_frames > 0) {
|
||||
RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesSentInPermille",
|
||||
static_cast<int>(
|
||||
(frames.numKeyFrames * 1000.0f / total_frames) + 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
int ViEEncoder::Owner() const {
|
||||
return channel_id_;
|
||||
}
|
||||
|
@ -193,6 +193,8 @@ class ViEEncoder
|
||||
private:
|
||||
bool EncoderPaused() const EXCLUSIVE_LOCKS_REQUIRED(data_cs_);
|
||||
|
||||
void UpdateHistograms();
|
||||
|
||||
int32_t engine_id_;
|
||||
const int channel_id_;
|
||||
const uint32_t number_of_cores_;
|
||||
@ -235,6 +237,7 @@ class ViEEncoder
|
||||
QMVideoSettingsCallback* qm_callback_;
|
||||
bool video_suspended_ GUARDED_BY(data_cs_);
|
||||
I420FrameCallback* pre_encode_callback_ GUARDED_BY(callback_cs_);
|
||||
const int64_t start_ms_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
Loading…
x
Reference in New Issue
Block a user