| 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);
|
|
|