Index: webrtc/video/full_stack.cc |
diff --git a/webrtc/video/full_stack.cc b/webrtc/video/full_stack.cc |
index ad1b5c6356557e3e4152b1dbd0f3c8c0f31ede2c..a03344e635516444ac2aaf40b09fb27f1bf58a6a 100644 |
--- a/webrtc/video/full_stack.cc |
+++ b/webrtc/video/full_stack.cc |
@@ -18,6 +18,7 @@ |
#include "webrtc/base/thread_annotations.h" |
#include "webrtc/call.h" |
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
+#include "webrtc/frame_callback.h" |
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" |
#include "webrtc/system_wrappers/interface/clock.h" |
#include "webrtc/system_wrappers/interface/cpu_info.h" |
@@ -37,6 +38,7 @@ |
namespace webrtc { |
static const int kFullStackTestDurationSecs = 60; |
+static const int kSendStatsPollingIntervalMs = 1000; |
struct FullStackTestParams { |
const char* test_label; |
@@ -63,7 +65,8 @@ class FullStackTest : public test::CallTest { |
class VideoAnalyzer : public PacketReceiver, |
public newapi::Transport, |
public VideoRenderer, |
- public VideoCaptureInput { |
+ public VideoCaptureInput, |
+ public EncodedFrameObserver { |
public: |
VideoAnalyzer(VideoCaptureInput* input, |
Transport* transport, |
@@ -74,6 +77,7 @@ class VideoAnalyzer : public PacketReceiver, |
: input_(input), |
transport_(transport), |
receiver_(nullptr), |
+ send_stream_(nullptr), |
test_label_(test_label), |
frames_to_process_(duration_frames), |
frames_recorded_(0), |
@@ -110,6 +114,10 @@ class VideoAnalyzer : public PacketReceiver, |
EXPECT_TRUE(thread->Start()); |
comparison_thread_pool_.push_back(thread.release()); |
} |
+ |
+ stats_polling_thread_ = |
+ ThreadWrapper::CreateThread(&PollStatsThread, this, "StatsPoller"); |
+ EXPECT_TRUE(stats_polling_thread_->Start()); |
} |
~VideoAnalyzer() { |
@@ -173,6 +181,12 @@ class VideoAnalyzer : public PacketReceiver, |
return transport_->SendRtcp(packet, length); |
} |
+ void EncodedFrameCallback(const EncodedFrame& frame) override { |
+ rtc::CritScope lock(&comparison_lock_); |
+ if (frames_recorded_ < frames_to_process_) |
+ encoded_frame_size_.AddSample(frame.length_); |
+ } |
+ |
void RenderFrame(const VideoFrame& video_frame, |
int time_to_render_ms) override { |
int64_t render_time_ms = |
@@ -222,11 +236,18 @@ class VideoAnalyzer : public PacketReceiver, |
<< "Analyzer stalled while waiting for test to finish."; |
last_frames_processed = frames_processed; |
} |
+ |
+ // Signal stats polling thread if that is still waiting and stop it now, |
+ // since it uses the send_stream_ reference that might be reclaimed after |
+ // returning from this method. |
+ done_->Set(); |
+ EXPECT_TRUE(stats_polling_thread_->Stop()); |
} |
VideoCaptureInput* input_; |
Transport* transport_; |
PacketReceiver* receiver_; |
+ VideoSendStream* send_stream_; |
private: |
struct FrameComparison { |
@@ -265,15 +286,39 @@ class VideoAnalyzer : public PacketReceiver, |
recv_times_.erase(reference.timestamp()); |
rtc::CritScope crit(&comparison_lock_); |
- comparisons_.push_back(FrameComparison(reference, |
- render, |
- dropped, |
- send_time_ms, |
- recv_time_ms, |
+ comparisons_.push_back(FrameComparison(reference, render, dropped, |
+ send_time_ms, recv_time_ms, |
render_time_ms)); |
comparison_available_event_->Set(); |
} |
+ static bool PollStatsThread(void* obj) { |
+ return static_cast<VideoAnalyzer*>(obj)->PollStats(); |
+ } |
+ |
+ bool PollStats() { |
+ switch (done_->Wait(kSendStatsPollingIntervalMs)) { |
+ case kEventSignaled: |
+ case kEventError: |
+ done_->Set(); // Make sure main thread is also signaled. |
+ return false; |
+ case kEventTimeout: |
+ break; |
+ default: |
+ RTC_NOTREACHED(); |
+ } |
+ |
+ VideoSendStream::Stats stats = send_stream_->GetStats(); |
+ |
+ rtc::CritScope crit(&comparison_lock_); |
+ encode_frame_rate_.AddSample(stats.encode_frame_rate); |
+ encode_time_ms.AddSample(stats.avg_encode_time_ms); |
+ encode_usage_percent.AddSample(stats.encode_usage_percent); |
+ media_bitrate_bps.AddSample(stats.media_bitrate_bps); |
+ |
+ return true; |
+ } |
+ |
static bool FrameComparisonThread(void* obj) { |
return static_cast<VideoAnalyzer*>(obj)->CompareFrames(); |
} |
@@ -358,6 +403,12 @@ class VideoAnalyzer : public PacketReceiver, |
PrintResult("receiver_time", receiver_time_, " ms"); |
PrintResult("total_delay_incl_network", end_to_end_, " ms"); |
PrintResult("time_between_rendered_frames", rendered_delta_, " ms"); |
+ PrintResult("encoded_frame_size", encoded_frame_size_, " bytes"); |
+ PrintResult("encode_frame_rate", encode_frame_rate_, " fps"); |
+ PrintResult("encode_time", encode_time_ms, " ms"); |
+ PrintResult("encode_usage_percent", encode_usage_percent, " percent"); |
+ PrintResult("media_bitrate", media_bitrate_bps, " bps"); |
+ |
EXPECT_GT(psnr_.Mean(), avg_psnr_threshold_); |
EXPECT_GT(ssim_.Mean(), avg_ssim_threshold_); |
} |
@@ -397,12 +448,18 @@ class VideoAnalyzer : public PacketReceiver, |
} |
const char* const test_label_; |
- test::Statistics sender_time_; |
- test::Statistics receiver_time_; |
- test::Statistics psnr_; |
- test::Statistics ssim_; |
- test::Statistics end_to_end_; |
- test::Statistics rendered_delta_; |
+ test::Statistics sender_time_ GUARDED_BY(comparison_lock_); |
+ test::Statistics receiver_time_ GUARDED_BY(comparison_lock_); |
+ test::Statistics psnr_ GUARDED_BY(comparison_lock_); |
+ test::Statistics ssim_ GUARDED_BY(comparison_lock_); |
+ test::Statistics end_to_end_ GUARDED_BY(comparison_lock_); |
+ test::Statistics rendered_delta_ GUARDED_BY(comparison_lock_); |
+ test::Statistics encoded_frame_size_ GUARDED_BY(comparison_lock_); |
+ test::Statistics encode_frame_rate_ GUARDED_BY(comparison_lock_); |
+ test::Statistics encode_time_ms GUARDED_BY(comparison_lock_); |
+ test::Statistics encode_usage_percent GUARDED_BY(comparison_lock_); |
+ test::Statistics media_bitrate_bps GUARDED_BY(comparison_lock_); |
+ |
const int frames_to_process_; |
int frames_recorded_; |
int frames_processed_; |
@@ -421,6 +478,7 @@ class VideoAnalyzer : public PacketReceiver, |
rtc::CriticalSection comparison_lock_; |
std::vector<ThreadWrapper*> comparison_thread_pool_; |
+ rtc::scoped_ptr<ThreadWrapper> stats_polling_thread_; |
const rtc::scoped_ptr<EventWrapper> comparison_available_event_; |
std::deque<FrameComparison> comparisons_ GUARDED_BY(comparison_lock_); |
const rtc::scoped_ptr<EventWrapper> done_; |
@@ -478,8 +536,11 @@ void FullStackTest::RunTest(const FullStackTestParams& params) { |
receive_configs_[0].rtp.rtx[kSendRtxPayloadType].payload_type = |
kSendRtxPayloadType; |
+ for (auto& config : receive_configs_) |
+ config.pre_decode_callback = &analyzer; |
CreateStreams(); |
analyzer.input_ = send_stream_->Input(); |
+ analyzer.send_stream_ = send_stream_; |
if (params.screenshare) { |
std::vector<std::string> slides; |