Skip to content

Commit

Permalink
Add dropped frames metric on the receive side
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Erik Språng <[email protected]>
Commit-Queue: Ilya Nikolaevskiy <[email protected]>
Cr-Commit-Position: refs/heads/master@{#22132}
  • Loading branch information
Ilya Nikolaevskiy authored and Commit Bot committed Feb 21, 2018
1 parent 8f83b42 commit d397a0d
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 6 deletions.
21 changes: 21 additions & 0 deletions modules/video_coding/packet_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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_;

Expand Down Expand Up @@ -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_
Expand Down Expand Up @@ -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
15 changes: 15 additions & 0 deletions modules/video_coding/packet_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define MODULES_VIDEO_CODING_PACKET_BUFFER_H_

#include <memory>
#include <queue>
#include <set>
#include <vector>

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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_);
Expand All @@ -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;
};

Expand Down
72 changes: 66 additions & 6 deletions modules/video_coding/video_packet_buffer_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down
15 changes: 15 additions & 0 deletions video/receive_statistics_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ void ReceiveStatisticsProxy::UpdateHistograms() {
<< stream_duration_sec << "\n";
}

RTC_LOG(LS_INFO) << "Frames decoded " << stats_.frames_decoded;

if (num_unique_frames_) {
int num_dropped_frames = *num_unique_frames_ - stats_.frames_decoded;
RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DroppedFrames.Receiver",
num_dropped_frames);
RTC_LOG(LS_INFO) << "WebRTC.Video.DroppedFrames.Receiver "
<< num_dropped_frames;
}

if (first_report_block_time_ms_ != -1 &&
((clock_->TimeInMilliseconds() - first_report_block_time_ms_) / 1000) >=
metrics::kMinRunTimeInSeconds) {
Expand Down Expand Up @@ -579,6 +589,11 @@ void ReceiveStatisticsProxy::OnFrameBufferTimingsUpdated(
delay_counter_.Add(target_delay_ms + avg_rtt_ms_ / 2);
}

void ReceiveStatisticsProxy::OnUniqueFramesCounted(int num_unique_frames) {
rtc::CritScope lock(&crit_);
num_unique_frames_.emplace(num_unique_frames);
}

void ReceiveStatisticsProxy::OnTimingFrameInfoUpdated(
const TimingFrameInfo& info) {
rtc::CritScope lock(&crit_);
Expand Down
3 changes: 3 additions & 0 deletions video/receive_statistics_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
void OnPreDecode(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info);

void OnUniqueFramesCounted(int num_unique_frames);

// Indicates video stream has been paused (no incoming packets).
void OnStreamInactive();

Expand Down Expand Up @@ -188,6 +190,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
// called from const GetStats().
mutable rtc::MovingMaxCounter<TimingFrameInfo> timing_frame_info_counter_
RTC_GUARDED_BY(&crit_);
rtc::Optional<int> num_unique_frames_ RTC_GUARDED_BY(crit_);
};

} // namespace webrtc
Expand Down
4 changes: 4 additions & 0 deletions video/rtp_video_stream_receiver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,10 @@ void RtpVideoStreamReceiver::SignalNetworkState(NetworkState state) {
: RtcpMode::kOff);
}

int RtpVideoStreamReceiver::GetUniqueFramesSeen() const {
return packet_buffer_->GetUniqueFramesSeen();
}

void RtpVideoStreamReceiver::StartReceive() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_task_checker_);
receiving_ = true;
Expand Down
3 changes: 3 additions & 0 deletions video/rtp_video_stream_receiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ class RtpVideoStreamReceiver : public RtpData,

void SignalNetworkState(NetworkState state);

// Returns number of different frames seen in the packet buffer.
int GetUniqueFramesSeen() const;

// Implements RtpPacketSinkInterface.
void OnRtpPacket(const RtpPacketReceived& packet) override;

Expand Down
3 changes: 3 additions & 0 deletions video/video_receive_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ void VideoReceiveStream::Stop() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
rtp_video_stream_receiver_.StopReceive();

stats_proxy_.OnUniqueFramesCounted(
rtp_video_stream_receiver_.GetUniqueFramesSeen());

frame_buffer_->Stop();
call_stats_->DeregisterStatsObserver(this);
call_stats_->DeregisterStatsObserver(&rtp_video_stream_receiver_);
Expand Down

0 comments on commit d397a0d

Please sign in to comment.