Index: webrtc/video/video_quality_test.cc |
diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc |
index 057a8a2ab71aa2d2be32b1e19e65e31860cf3138..3f5f37ebd3d9125bd9d1624ff868cf8cf4f3f154 100644 |
--- a/webrtc/video/video_quality_test.cc |
+++ b/webrtc/video/video_quality_test.cc |
@@ -64,11 +64,14 @@ class VideoAnalyzer : public PacketReceiver, |
graph_data_output_file_(graph_data_output_file), |
graph_title_(graph_title), |
ssrc_to_analyze_(ssrc_to_analyze), |
+ pre_encode_proxy_(this), |
encode_timing_proxy_(this), |
frames_to_process_(duration_frames), |
frames_recorded_(0), |
frames_processed_(0), |
dropped_frames_(0), |
+ dropped_frames_before_first_encode_(0), |
+ dropped_frames_before_rendering_(0), |
last_render_time_(0), |
rtp_timestamp_delta_(0), |
avg_psnr_threshold_(avg_psnr_threshold), |
@@ -144,18 +147,26 @@ class VideoAnalyzer : public PacketReceiver, |
void IncomingCapturedFrame(const VideoFrame& video_frame) override { |
VideoFrame copy = video_frame; |
copy.set_timestamp(copy.ntp_time_ms() * 90); |
- |
{ |
rtc::CritScope lock(&crit_); |
- if (!first_send_timestamp_ && rtp_timestamp_delta_ == 0) |
- first_send_timestamp_ = rtc::Optional<uint32_t>(copy.timestamp()); |
- |
frames_.push_back(copy); |
} |
input_->IncomingCapturedFrame(video_frame); |
} |
+ void PreEncodeOnFrame(const VideoFrame& video_frame) { |
+ rtc::CritScope lock(&crit_); |
+ if (!first_send_timestamp_ && rtp_timestamp_delta_ == 0) { |
+ while (frames_.front().timestamp() != video_frame.timestamp()) { |
+ ++dropped_frames_before_first_encode_; |
+ frames_.pop_front(); |
+ RTC_CHECK(!frames_.empty()); |
+ } |
+ first_send_timestamp_ = rtc::Optional<uint32_t>(video_frame.timestamp()); |
+ } |
+ } |
+ |
bool SendRtp(const uint8_t* packet, |
size_t length, |
const PacketOptions& options) override { |
@@ -204,9 +215,18 @@ class VideoAnalyzer : public PacketReceiver, |
wrap_handler_.Unwrap(video_frame.timestamp() - rtp_timestamp_delta_); |
while (wrap_handler_.Unwrap(frames_.front().timestamp()) < send_timestamp) { |
+ if (last_rendered_frame_.IsZeroSize()) { |
+ // No previous frame rendered, this one was dropped after sending but |
+ // before rendering. |
+ ++dropped_frames_before_rendering_; |
+ frames_.pop_front(); |
+ RTC_CHECK(!frames_.empty()); |
+ continue; |
+ } |
AddFrameComparison(frames_.front(), last_rendered_frame_, true, |
render_time_ms); |
frames_.pop_front(); |
+ RTC_DCHECK(!frames_.empty()); |
} |
VideoFrame reference_frame = frames_.front(); |
@@ -268,6 +288,9 @@ class VideoAnalyzer : public PacketReceiver, |
stats_polling_thread_.Stop(); |
} |
+ rtc::VideoSinkInterface<VideoFrame>* pre_encode_proxy() { |
+ return &pre_encode_proxy_; |
+ } |
EncodedFrameObserver* encode_timing_proxy() { return &encode_timing_proxy_; } |
VideoCaptureInput* input_; |
@@ -351,11 +374,26 @@ class VideoAnalyzer : public PacketReceiver, |
VideoAnalyzer* const parent_; |
}; |
+ // This class receives the send-side OnFrame callback and is provided to not |
+ // conflict with the receiver-side renderer callback. |
+ class PreEncodeProxy : public rtc::VideoSinkInterface<VideoFrame> { |
+ public: |
+ explicit PreEncodeProxy(VideoAnalyzer* parent) : parent_(parent) {} |
+ |
+ void OnFrame(const VideoFrame& video_frame) override { |
+ parent_->PreEncodeOnFrame(video_frame); |
+ } |
+ |
+ private: |
+ VideoAnalyzer* const parent_; |
+ }; |
+ |
void AddFrameComparison(const VideoFrame& reference, |
const VideoFrame& render, |
bool dropped, |
int64_t render_time_ms) |
EXCLUSIVE_LOCKS_REQUIRED(crit_) { |
+ RTC_DCHECK(!render.IsZeroSize()); |
int64_t reference_timestamp = wrap_handler_.Unwrap(reference.timestamp()); |
int64_t send_time_ms = send_times_[reference_timestamp]; |
send_times_.erase(reference_timestamp); |
@@ -488,8 +526,6 @@ class VideoAnalyzer : public PacketReceiver, |
PrintResult("psnr", psnr_, " dB"); |
PrintResult("ssim", ssim_, " score"); |
PrintResult("sender_time", sender_time_, " ms"); |
- printf("RESULT dropped_frames: %s = %d frames\n", test_label_.c_str(), |
- dropped_frames_); |
PrintResult("receiver_time", receiver_time_, " ms"); |
PrintResult("total_delay_incl_network", end_to_end_, " ms"); |
PrintResult("time_between_rendered_frames", rendered_delta_, " ms"); |
@@ -499,6 +535,13 @@ class VideoAnalyzer : public PacketReceiver, |
PrintResult("encode_usage_percent", encode_usage_percent, " percent"); |
PrintResult("media_bitrate", media_bitrate_bps, " bps"); |
+ printf("RESULT dropped_frames: %s = %d frames\n", test_label_.c_str(), |
+ dropped_frames_); |
+ printf("RESULT dropped_frames_before_first_encode: %s = %d frames\n", |
+ test_label_.c_str(), dropped_frames_before_first_encode_); |
+ printf("RESULT dropped_frames_before_rendering: %s = %d frames\n", |
+ test_label_.c_str(), dropped_frames_before_rendering_); |
+ |
EXPECT_GT(psnr_.Mean(), avg_psnr_threshold_); |
EXPECT_GT(ssim_.Mean(), avg_ssim_threshold_); |
} |
@@ -594,6 +637,7 @@ class VideoAnalyzer : public PacketReceiver, |
FILE* const graph_data_output_file_; |
const std::string graph_title_; |
const uint32_t ssrc_to_analyze_; |
+ PreEncodeProxy pre_encode_proxy_; |
OnEncodeTimingProxy encode_timing_proxy_; |
std::vector<Sample> samples_ GUARDED_BY(comparison_lock_); |
std::map<int64_t, int> samples_encode_time_ms_ GUARDED_BY(comparison_lock_); |
@@ -613,6 +657,8 @@ class VideoAnalyzer : public PacketReceiver, |
int frames_recorded_; |
int frames_processed_; |
int dropped_frames_; |
+ int dropped_frames_before_first_encode_; |
+ int dropped_frames_before_rendering_; |
int64_t last_render_time_; |
uint32_t rtp_timestamp_delta_; |
@@ -1006,6 +1052,7 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { |
SetupCommon(&analyzer, &recv_transport); |
video_receive_configs_[params_.ss.selected_stream].renderer = &analyzer; |
+ video_send_config_.pre_encode_callback = analyzer.pre_encode_proxy(); |
for (auto& config : video_receive_configs_) |
config.pre_decode_callback = &analyzer; |
RTC_DCHECK(!video_send_config_.post_encode_callback); |