Add dropped frames metric on the receive side

Reported to UMA and logged for at the end of the call.

Bug: webrtc:8355
Change-Id: I4ef31bf9e55feaba9cf28be5cb4fcfae929c7179
Reviewed-on: https://webrtc-review.googlesource.com/53760
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22132}
This commit is contained in:
Ilya Nikolaevskiy
2018-02-21 15:57:09 +01:00
committed by Commit Bot
parent 8f83b42946
commit d397a0d46e
8 changed files with 130 additions and 6 deletions

View File

@ -48,6 +48,7 @@ PacketBuffer::PacketBuffer(Clock* clock,
data_buffer_(start_buffer_size),
sequence_buffer_(start_buffer_size),
received_frame_callback_(received_frame_callback),
unique_frames_seen_(0),
sps_pps_idr_is_h264_keyframe_(
field_trial::IsEnabled("WebRTC-SpsPpsIdrIsH264Keyframe")) {
RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
@ -65,6 +66,8 @@ bool PacketBuffer::InsertPacket(VCMPacket* packet) {
{
rtc::CritScope lock(&crit_);
OnTimestampReceived(packet->timestamp);
uint16_t seq_num = packet->seqNum;
size_t index = seq_num % size_;
@ -207,6 +210,11 @@ rtc::Optional<int64_t> PacketBuffer::LastReceivedKeyframePacketMs() const {
return last_received_keyframe_packet_ms_;
}
int PacketBuffer::GetUniqueFramesSeen() const {
rtc::CritScope lock(&crit_);
return unique_frames_seen_;
}
bool PacketBuffer::ExpandBufferSize() {
if (size_ == max_size_) {
RTC_LOG(LS_WARNING) << "PacketBuffer is already at max size (" << max_size_
@ -484,5 +492,18 @@ void PacketBuffer::UpdateMissingPackets(uint16_t seq_num) {
}
}
void PacketBuffer::OnTimestampReceived(uint32_t rtp_timestamp) {
const size_t kMaxTimestampsHistory = 1000;
if (rtp_timestamps_history_set_.insert(rtp_timestamp).second) {
rtp_timestamps_history_queue_.push(rtp_timestamp);
++unique_frames_seen_;
if (rtp_timestamps_history_set_.size() > kMaxTimestampsHistory) {
uint32_t discarded_timestamp = rtp_timestamps_history_queue_.front();
rtp_timestamps_history_set_.erase(discarded_timestamp);
rtp_timestamps_history_queue_.pop();
}
}
}
} // namespace video_coding
} // namespace webrtc

View File

@ -12,6 +12,7 @@
#define MODULES_VIDEO_CODING_PACKET_BUFFER_H_
#include <memory>
#include <queue>
#include <set>
#include <vector>
@ -61,6 +62,9 @@ class PacketBuffer {
rtc::Optional<int64_t> LastReceivedPacketMs() const;
rtc::Optional<int64_t> LastReceivedKeyframePacketMs() const;
// Returns number of different frames seen in the packet buffer
int GetUniqueFramesSeen() const;
int AddRef() const;
int Release() const;
@ -126,6 +130,10 @@ class PacketBuffer {
void UpdateMissingPackets(uint16_t seq_num)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
// Counts unique received timestamps and updates |unique_frames_seen_|.
void OnTimestampReceived(uint32_t rtp_timestamp)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
rtc::CriticalSection crit_;
// Buffer size_ and max_size_ must always be a power of two.
@ -156,6 +164,8 @@ class PacketBuffer {
rtc::Optional<int64_t> last_received_keyframe_packet_ms_
RTC_GUARDED_BY(crit_);
int unique_frames_seen_ RTC_GUARDED_BY(crit_);
rtc::Optional<uint16_t> newest_inserted_seq_num_ RTC_GUARDED_BY(crit_);
std::set<uint16_t, DescendingSeqNumComp<uint16_t>> missing_packets_
RTC_GUARDED_BY(crit_);
@ -164,6 +174,11 @@ class PacketBuffer {
// RTP timestamp to treat the corresponding frame as a keyframe.
const bool sps_pps_idr_is_h264_keyframe_;
// Stores several last seen unique timestamps for quick search.
std::set<uint32_t> rtp_timestamps_history_set_ RTC_GUARDED_BY(crit_);
// Stores the same unique timestamps in the order of insertion.
std::queue<uint32_t> rtp_timestamps_history_queue_ RTC_GUARDED_BY(crit_);
mutable volatile int ref_count_ = 0;
};

View File

@ -54,14 +54,16 @@ class TestPacketBuffer : public ::testing::Test,
enum IsFirst { kFirst, kNotFirst };
enum IsLast { kLast, kNotLast };
bool Insert(uint16_t seq_num, // packet sequence number
IsKeyFrame keyframe, // is keyframe
IsFirst first, // is first packet of frame
IsLast last, // is last packet of frame
int data_size = 0, // size of data
uint8_t* data = nullptr) { // data pointer
bool Insert(uint16_t seq_num, // packet sequence number
IsKeyFrame keyframe, // is keyframe
IsFirst first, // is first packet of frame
IsLast last, // is last packet of frame
int data_size = 0, // size of data
uint8_t* data = nullptr, // data pointer
uint32_t timestamp = 123u) { // rtp timestamp
VCMPacket packet;
packet.codec = kVideoCodecGeneric;
packet.timestamp = timestamp;
packet.seqNum = seq_num;
packet.frameType =
keyframe == kKeyFrame ? kVideoFrameKey : kVideoFrameDelta;
@ -195,6 +197,64 @@ TEST_F(TestPacketBuffer, FrameSize) {
EXPECT_EQ(20UL, frames_from_callback_.begin()->second->size());
}
TEST_F(TestPacketBuffer, CountsUniqueFrames) {
const uint16_t seq_num = Rand();
ASSERT_EQ(0, packet_buffer_->GetUniqueFramesSeen());
EXPECT_TRUE(Insert(seq_num, kKeyFrame, kFirst, kNotLast, 0, nullptr, 100));
ASSERT_EQ(1, packet_buffer_->GetUniqueFramesSeen());
// Still the same frame.
EXPECT_TRUE(
Insert(seq_num + 1, kKeyFrame, kNotFirst, kLast, 0, nullptr, 100));
ASSERT_EQ(1, packet_buffer_->GetUniqueFramesSeen());
// Second frame.
EXPECT_TRUE(
Insert(seq_num + 2, kKeyFrame, kFirst, kNotLast, 0, nullptr, 200));
ASSERT_EQ(2, packet_buffer_->GetUniqueFramesSeen());
EXPECT_TRUE(
Insert(seq_num + 3, kKeyFrame, kNotFirst, kLast, 0, nullptr, 200));
ASSERT_EQ(2, packet_buffer_->GetUniqueFramesSeen());
// Old packet.
EXPECT_TRUE(
Insert(seq_num + 1, kKeyFrame, kNotFirst, kLast, 0, nullptr, 100));
ASSERT_EQ(2, packet_buffer_->GetUniqueFramesSeen());
// Missing middle packet.
EXPECT_TRUE(
Insert(seq_num + 4, kKeyFrame, kFirst, kNotLast, 0, nullptr, 300));
EXPECT_TRUE(
Insert(seq_num + 6, kKeyFrame, kNotFirst, kLast, 0, nullptr, 300));
ASSERT_EQ(3, packet_buffer_->GetUniqueFramesSeen());
}
TEST_F(TestPacketBuffer, HasHistoryOfUniqueFrames) {
const int kNumFrames = 1500;
const int kRequiredHistoryLength = 1000;
const uint16_t seq_num = Rand();
const uint32_t timestamp = 0xFFFFFFF0; // Large enough to cause wrap-around.
for (int i = 0; i < kNumFrames; ++i) {
EXPECT_TRUE(Insert(seq_num + i, kKeyFrame, kFirst, kNotLast, 0, nullptr,
timestamp + 10 * i));
}
ASSERT_EQ(kNumFrames, packet_buffer_->GetUniqueFramesSeen());
// Old packets within history should not affect number of seen unique frames.
for (int i = kNumFrames - kRequiredHistoryLength; i < kNumFrames; ++i) {
EXPECT_TRUE(Insert(seq_num + i, kKeyFrame, kFirst, kNotLast, 0, nullptr,
timestamp + 10 * i));
}
ASSERT_EQ(kNumFrames, packet_buffer_->GetUniqueFramesSeen());
// Very old packets should be treated as unique.
EXPECT_TRUE(
Insert(seq_num, kKeyFrame, kFirst, kNotLast, 0, nullptr, timestamp));
ASSERT_EQ(kNumFrames + 1, packet_buffer_->GetUniqueFramesSeen());
}
TEST_F(TestPacketBuffer, ExpandBuffer) {
const uint16_t seq_num = Rand();