[PCLF] Rescale frame to the requested resolution before passing it to analyzer

Bug: b/240540204
Change-Id: Idafa74021dd136d8ec9fd54cabaa7f0d49d379d9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280944
Reviewed-by: Andrey Logvin <landrey@google.com>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38498}
diff --git a/test/pc/e2e/analyzer/video/analyzing_video_sink.cc b/test/pc/e2e/analyzer/video/analyzing_video_sink.cc
index 97afda6..9534c38 100644
--- a/test/pc/e2e/analyzer/video/analyzing_video_sink.cc
+++ b/test/pc/e2e/analyzer/video/analyzing_video_sink.cc
@@ -30,6 +30,7 @@
 
 namespace webrtc {
 namespace webrtc_pc_e2e {
+namespace {
 
 using VideoSubscription = ::webrtc::webrtc_pc_e2e::
     PeerConnectionE2EQualityTestFixture::VideoSubscription;
@@ -38,6 +39,35 @@
 using VideoConfig =
     ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig;
 
+// Scales video frame to `required_resolution` if necessary. Crashes if video
+// frame and `required_resolution` have different aspect ratio.
+VideoFrame ScaleVideoFrame(const VideoFrame& frame,
+                           VideoResolution required_resolution) {
+  if (required_resolution.width() == static_cast<size_t>(frame.width()) &&
+      required_resolution.height() == static_cast<size_t>(frame.height())) {
+    return frame;
+  }
+
+  RTC_CHECK_LE(std::abs(static_cast<double>(required_resolution.width()) /
+                            required_resolution.height() -
+                        static_cast<double>(frame.width()) / frame.height()),
+               2 * std::numeric_limits<double>::epsilon())
+      << "Received frame has different aspect ratio compared to requested "
+      << "video resolution: required resolution="
+      << required_resolution.ToString()
+      << "; actual resolution=" << frame.width() << "x" << frame.height();
+
+  rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
+      required_resolution.width(), required_resolution.height()));
+  scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420());
+
+  VideoFrame scaled_frame = frame;
+  scaled_frame.set_video_frame_buffer(scaled_buffer);
+  return scaled_frame;
+}
+
+}  // namespace
+
 AnalyzingVideoSink::AnalyzingVideoSink(absl::string_view peer_name,
                                        Clock* clock,
                                        VideoQualityAnalyzerInterface& analyzer,
@@ -78,23 +108,30 @@
     // This is dummy frame, so we  don't need to process it further.
     return;
   }
-  // Copy entire video frame including video buffer to ensure that analyzer
-  // won't hold any WebRTC internal buffers.
+
+  if (frame.id() == VideoFrame::kNotSetId) {
+    // If frame ID is unknown we can't get required render resolution, so pass
+    // to the analyzer in the actual resolution of the frame.
+    AnalyzeFrame(frame);
+  } else {
+    std::string stream_label = analyzer_->GetStreamLabel(frame.id());
+    SinksDescriptor* sinks_descriptor = PopulateSinks(stream_label);
+    RTC_CHECK(sinks_descriptor != nullptr);
+
+    VideoFrame scaled_frame =
+        ScaleVideoFrame(frame, sinks_descriptor->resolution);
+    AnalyzeFrame(scaled_frame);
+    for (auto& sink : sinks_descriptor->sinks) {
+      sink->OnFrame(scaled_frame);
+    }
+  }
+}
+
+void AnalyzingVideoSink::AnalyzeFrame(const VideoFrame& frame) {
   VideoFrame frame_copy = frame;
   frame_copy.set_video_frame_buffer(
       I420Buffer::Copy(*frame.video_frame_buffer()->ToI420()));
   analyzer_->OnFrameRendered(peer_name_, frame_copy);
-
-  if (frame.id() != VideoFrame::kNotSetId) {
-    std::string stream_label = analyzer_->GetStreamLabel(frame.id());
-    SinksDescriptor* sinks_descriptor = PopulateSinks(stream_label);
-    if (sinks_descriptor == nullptr) {
-      return;
-    }
-    for (auto& sink : sinks_descriptor->sinks) {
-      sink->OnFrame(frame);
-    }
-  }
 }
 
 AnalyzingVideoSink::SinksDescriptor* AnalyzingVideoSink::PopulateSinks(
diff --git a/test/pc/e2e/analyzer/video/analyzing_video_sink.h b/test/pc/e2e/analyzer/video/analyzing_video_sink.h
index 17b58fe2..0508a6b 100644
--- a/test/pc/e2e/analyzer/video/analyzing_video_sink.h
+++ b/test/pc/e2e/analyzer/video/analyzing_video_sink.h
@@ -66,6 +66,10 @@
     std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
   };
 
+  // Creates full copy of the frame to free any frame owned internal buffers and
+  // passes created copy to analyzer. Uses `I420Buffer` to represent frame
+  // content.
+  void AnalyzeFrame(const VideoFrame& frame);
   // Populates sink for specified stream and caches them in `stream_sinks_`.
   SinksDescriptor* PopulateSinks(absl::string_view stream_label);
 
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
index 7e3806f..772b686 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
@@ -434,7 +434,8 @@
   used_decoder.last_frame_id = frame.id();
   used_decoder.switched_on_at = now;
   used_decoder.switched_from_at = now;
-  it->second.OnFrameDecoded(peer_index, now, used_decoder);
+  it->second.OnFrameDecoded(peer_index, now, frame.width(), frame.height(),
+                            used_decoder);
 }
 
 void DefaultVideoQualityAnalyzer::OnFrameRendered(
@@ -490,8 +491,7 @@
   stream_frame_counters_.at(stats_key).rendered++;
 
   // Update current frame stats.
-  frame_in_flight->OnFrameRendered(peer_index, Now(), frame.width(),
-                                   frame.height());
+  frame_in_flight->OnFrameRendered(peer_index, Now());
 
   // After we received frame here we need to check if there are any dropped
   // frames between this one and last one, that was rendered for this video
@@ -1010,7 +1010,7 @@
                              ImprovementDirection::kSmallerIsBetter,
                              metric_metadata);
   metrics_logger_->LogMetric(
-      "pixels_per_frame", test_case_name, stats.resolution_of_rendered_frame,
+      "pixels_per_frame", test_case_name, stats.resolution_of_decoded_frame,
       Unit::kCount, ImprovementDirection::kBiggerIsBetter, metric_metadata);
   metrics_logger_->LogSingleValueMetric(
       "min_psnr_dB", test_case_name,
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
index 968c6c6..6b24dab 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
@@ -129,9 +129,13 @@
 
 void FrameInFlight::OnFrameDecoded(size_t peer,
                                    webrtc::Timestamp time,
+                                   int width,
+                                   int height,
                                    const StreamCodecInfo& used_decoder) {
   receiver_stats_[peer].decode_end_time = time;
   receiver_stats_[peer].used_decoder = used_decoder;
+  receiver_stats_[peer].decoded_frame_width = width;
+  receiver_stats_[peer].decoded_frame_height = height;
 }
 
 void FrameInFlight::OnDecoderError(size_t peer,
@@ -148,13 +152,8 @@
   return it->second.decode_end_time.IsFinite();
 }
 
-void FrameInFlight::OnFrameRendered(size_t peer,
-                                    webrtc::Timestamp time,
-                                    int width,
-                                    int height) {
+void FrameInFlight::OnFrameRendered(size_t peer, webrtc::Timestamp time) {
   receiver_stats_[peer].rendered_time = time;
-  receiver_stats_[peer].rendered_frame_width = width;
-  receiver_stats_[peer].rendered_frame_height = height;
 }
 
 bool FrameInFlight::HasRenderedTime(size_t peer) const {
@@ -192,8 +191,8 @@
     stats.decode_end_time = receiver_stats->decode_end_time;
     stats.rendered_time = receiver_stats->rendered_time;
     stats.prev_frame_rendered_time = receiver_stats->prev_frame_rendered_time;
-    stats.rendered_frame_width = receiver_stats->rendered_frame_width;
-    stats.rendered_frame_height = receiver_stats->rendered_frame_height;
+    stats.decoded_frame_width = receiver_stats->decoded_frame_width;
+    stats.decoded_frame_height = receiver_stats->decoded_frame_height;
     stats.used_decoder = receiver_stats->used_decoder;
     stats.pre_decoded_frame_type = receiver_stats->frame_type;
     stats.pre_decoded_image_size = receiver_stats->encoded_image_size;
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
index 92c031a..f1db78f 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
@@ -37,8 +37,8 @@
   VideoFrameType frame_type = VideoFrameType::kEmptyFrame;
   DataSize encoded_image_size = DataSize::Bytes(0);
 
-  absl::optional<int> rendered_frame_width = absl::nullopt;
-  absl::optional<int> rendered_frame_height = absl::nullopt;
+  absl::optional<int> decoded_frame_width = absl::nullopt;
+  absl::optional<int> decoded_frame_height = absl::nullopt;
 
   // Can be not set if frame was dropped in the network.
   absl::optional<StreamCodecInfo> used_decoder = absl::nullopt;
@@ -101,15 +101,14 @@
 
   void OnFrameDecoded(size_t peer,
                       webrtc::Timestamp time,
+                      int width,
+                      int height,
                       const StreamCodecInfo& used_decoder);
   void OnDecoderError(size_t peer, const StreamCodecInfo& used_decoder);
 
   bool HasDecodeEndTime(size_t peer) const;
 
-  void OnFrameRendered(size_t peer,
-                       webrtc::Timestamp time,
-                       int width,
-                       int height);
+  void OnFrameRendered(size_t peer, webrtc::Timestamp time);
 
   bool HasRenderedTime(size_t peer) const;
 
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.cc
index 3b7dc40..514ef53 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator.cc
@@ -80,10 +80,10 @@
           << "Regular comparison has to have finite decode_end_time";
       RTC_DCHECK(comparison.frame_stats.rendered_time.IsFinite())
           << "Regular comparison has to have finite rendered_time";
-      RTC_DCHECK(comparison.frame_stats.rendered_frame_width.has_value())
-          << "Regular comparison has to have rendered_frame_width";
-      RTC_DCHECK(comparison.frame_stats.rendered_frame_height.has_value())
-          << "Regular comparison has to have rendered_frame_height";
+      RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
+          << "Regular comparison has to have decoded_frame_width";
+      RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
+          << "Regular comparison has to have decoded_frame_height";
       RTC_DCHECK(comparison.frame_stats.used_encoder.has_value())
           << "Regular comparison has to have used_encoder";
       RTC_DCHECK(comparison.frame_stats.used_decoder.has_value())
@@ -119,6 +119,13 @@
         RTC_DCHECK(comparison.frame_stats.used_decoder.has_value())
             << "Dropped frame comparison has to have used_decoder when "
             << "decode_end_time is set or decoder_failed is true";
+      } else if (comparison.frame_stats.decode_end_time.IsFinite()) {
+        RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
+            << "Dropped frame comparison has to have decoded_frame_width when "
+            << "decode_end_time is set";
+        RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
+            << "Dropped frame comparison has to have decoded_frame_height when "
+            << "decode_end_time is set";
       } else {
         RTC_DCHECK(!comparison.frame_stats.received_time.IsFinite())
             << "Dropped frame comparison can't have received_time when "
@@ -132,10 +139,6 @@
       }
       RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite())
           << "Dropped frame comparison can't have rendered_time";
-      RTC_DCHECK(!comparison.frame_stats.rendered_frame_width.has_value())
-          << "Dropped frame comparison can't have rendered_frame_width";
-      RTC_DCHECK(!comparison.frame_stats.rendered_frame_height.has_value())
-          << "Dropped frame comparison can't have rendered_frame_height";
       break;
     case FrameComparisonType::kFrameInFlight:
       // Frame in flight comparison may miss almost any FrameStats, but if
@@ -147,10 +150,6 @@
           << "Frame in flight comparison can't have rendered frame";
       RTC_DCHECK(!comparison.frame_stats.rendered_time.IsFinite())
           << "Frame in flight comparison can't have rendered_time";
-      RTC_DCHECK(!comparison.frame_stats.rendered_frame_width.has_value())
-          << "Frame in flight comparison can't have rendered_frame_width";
-      RTC_DCHECK(!comparison.frame_stats.rendered_frame_height.has_value())
-          << "Frame in flight comparison can't have rendered_frame_height";
 
       if (comparison.frame_stats.decode_end_time.IsFinite() ||
           comparison.frame_stats.decoder_failed) {
@@ -162,6 +161,14 @@
             << "decode_start_time when decode_end_time is finite or "
             << "decoder_failed is true.";
       }
+      if (comparison.frame_stats.decode_end_time.IsFinite()) {
+        RTC_DCHECK(comparison.frame_stats.decoded_frame_width.has_value())
+            << "Frame in flight comparison has to have decoded_frame_width "
+            << "when decode_end_time is set.";
+        RTC_DCHECK(comparison.frame_stats.decoded_frame_height.has_value())
+            << "Frame in flight comparison has to have decoded_frame_height "
+            << "when decode_end_time is set.";
+      }
       if (comparison.frame_stats.decode_start_time.IsFinite()) {
         RTC_DCHECK(comparison.frame_stats.received_time.IsFinite())
             << "Frame in flight comparison has to have finite received_time "
@@ -473,10 +480,6 @@
   if (comparison.type != FrameComparisonType::kDroppedFrame ||
       comparison.frame_stats.decoder_failed) {
     if (frame_stats.rendered_time.IsFinite()) {
-      stats->resolution_of_rendered_frame.AddSample(
-          StatsSample(*comparison.frame_stats.rendered_frame_width *
-                          *comparison.frame_stats.rendered_frame_height,
-                      frame_stats.rendered_time, metadata));
       stats->total_delay_incl_transport_ms.AddSample(
           StatsSample(frame_stats.rendered_time - frame_stats.captured_time,
                       frame_stats.received_time, metadata));
@@ -507,6 +510,14 @@
       stats->decode_time_ms.AddSample(StatsSample(
           frame_stats.decode_end_time - frame_stats.decode_start_time,
           frame_stats.decode_end_time, metadata));
+      stats->resolution_of_decoded_frame.AddSample(
+          StatsSample(*comparison.frame_stats.decoded_frame_width *
+                          *comparison.frame_stats.decoded_frame_height,
+                      frame_stats.decode_end_time, metadata));
+      stats->resolution_of_rendered_frame.AddSample(
+          StatsSample(*comparison.frame_stats.decoded_frame_width *
+                          *comparison.frame_stats.decoded_frame_height,
+                      frame_stats.decode_end_time, metadata));
     }
 
     if (frame_stats.prev_frame_rendered_time.IsFinite() &&
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator_test.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator_test.cc
index 3f9d1a4..c58d7d9 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator_test.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frames_comparator_test.cc
@@ -86,8 +86,8 @@
   frame_stats.used_encoder = Vp8CodecForOneFrame(1, frame_stats.encoded_time);
   frame_stats.used_decoder =
       Vp8CodecForOneFrame(1, frame_stats.decode_end_time);
-  frame_stats.rendered_frame_width = 10;
-  frame_stats.rendered_frame_height = 10;
+  frame_stats.decoded_frame_width = 10;
+  frame_stats.decoded_frame_height = 10;
   return frame_stats;
 }
 
@@ -102,8 +102,8 @@
 
   frame_stats.used_encoder = stats.used_encoder;
   frame_stats.used_decoder = stats.used_decoder;
-  frame_stats.rendered_frame_width = stats.rendered_frame_width;
-  frame_stats.rendered_frame_height = stats.rendered_frame_height;
+  frame_stats.decoded_frame_width = stats.decoded_frame_width;
+  frame_stats.decoded_frame_height = stats.decoded_frame_height;
 
   return frame_stats;
 }
@@ -174,7 +174,7 @@
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.at(stats_key).receive_to_render_time_ms),
                    30.0);
   EXPECT_DOUBLE_EQ(
-      GetFirstOrDie(stats.at(stats_key).resolution_of_rendered_frame), 100.0);
+      GetFirstOrDie(stats.at(stats_key).resolution_of_decoded_frame), 100.0);
 }
 
 TEST(
@@ -274,13 +274,13 @@
       frame_stats.captured_time + TimeDelta::Millis(50);
   frame_stats.used_decoder =
       Vp8CodecForOneFrame(1, frame_stats.decode_end_time);
+  frame_stats.decoded_frame_width = 10;
+  frame_stats.decoded_frame_height = 10;
   stats.push_back(frame_stats);
   // 6th stat
   frame_stats = ShiftStatsOn(frame_stats, TimeDelta::Millis(15));
   frame_stats.frame_id = 6;
   frame_stats.rendered_time = frame_stats.captured_time + TimeDelta::Millis(60);
-  frame_stats.rendered_frame_width = 10;
-  frame_stats.rendered_frame_height = 10;
   stats.push_back(frame_stats);
 
   comparator.Start(/*max_threads_count=*/1);
@@ -323,9 +323,9 @@
       << ToString(result_stats.receive_to_render_time_ms);
   EXPECT_EQ(result_stats.receive_to_render_time_ms.NumSamples(), 1);
 
-  EXPECT_DOUBLE_EQ(result_stats.resolution_of_rendered_frame.GetAverage(), 100)
-      << ToString(result_stats.resolution_of_rendered_frame);
-  EXPECT_EQ(result_stats.resolution_of_rendered_frame.NumSamples(), 1);
+  EXPECT_DOUBLE_EQ(result_stats.resolution_of_decoded_frame.GetAverage(), 100)
+      << ToString(result_stats.resolution_of_decoded_frame);
+  EXPECT_EQ(result_stats.resolution_of_decoded_frame.NumSamples(), 2);
 
   EXPECT_DOUBLE_EQ(result_stats.encode_frame_rate.GetEventsPerSecond(),
                    4.0 / 45 * 1000)
@@ -375,7 +375,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   expectEmpty(stats.target_encode_bitrate);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -434,7 +434,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   expectEmpty(stats.target_encode_bitrate);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -501,7 +501,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -569,7 +569,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -642,7 +642,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -692,6 +692,9 @@
   frame_stats.decode_start_time = captured_time + TimeDelta::Millis(40);
   // Frame decoded
   frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
+  frame_stats.decoded_frame_width = 200;
+  frame_stats.decoded_frame_height = 100;
+
   frame_stats.used_decoder =
       Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
 
@@ -719,7 +722,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  EXPECT_GE(GetFirstOrDie(stats.resolution_of_decoded_frame), 200 * 100.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -797,7 +800,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -859,7 +862,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   expectEmpty(stats.target_encode_bitrate);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -918,7 +921,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   expectEmpty(stats.target_encode_bitrate);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -985,7 +988,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -1053,7 +1056,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -1111,6 +1114,8 @@
   frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
   frame_stats.used_decoder =
       Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
+  frame_stats.decoded_frame_width = 200;
+  frame_stats.decoded_frame_height = 100;
 
   comparator.Start(/*max_threads_count=*/1);
   comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@@ -1136,7 +1141,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   expectEmpty(stats.recv_key_frame_size_bytes);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -1214,7 +1219,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  expectEmpty(stats.resolution_of_rendered_frame);
+  expectEmpty(stats.resolution_of_decoded_frame);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -1271,10 +1276,10 @@
   frame_stats.decode_end_time = captured_time + TimeDelta::Millis(50);
   frame_stats.used_decoder =
       Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
+  frame_stats.decoded_frame_width = 200;
+  frame_stats.decoded_frame_height = 100;
   // Frame rendered
   frame_stats.rendered_time = captured_time + TimeDelta::Millis(60);
-  frame_stats.rendered_frame_width = 200;
-  frame_stats.rendered_frame_height = 100;
 
   comparator.Start(/*max_threads_count=*/1);
   comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@@ -1300,7 +1305,7 @@
   expectEmpty(stats.skipped_between_rendered);
   expectEmpty(stats.freeze_time_ms);
   expectEmpty(stats.time_between_freezes_ms);
-  EXPECT_GE(GetFirstOrDie(stats.resolution_of_rendered_frame), 200 * 100.0);
+  EXPECT_GE(GetFirstOrDie(stats.resolution_of_decoded_frame), 200 * 100.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.target_encode_bitrate), 2000.0);
   EXPECT_DOUBLE_EQ(GetFirstOrDie(stats.recv_key_frame_size_bytes), 500.0);
   expectEmpty(stats.recv_delta_frame_size_bytes);
@@ -1356,8 +1361,8 @@
       Vp8CodecForOneFrame(frame_id, frame_stats.decode_end_time);
   // Frame rendered
   frame_stats.rendered_time = captured_time + TimeDelta::Millis(60);
-  frame_stats.rendered_frame_width = 200;
-  frame_stats.rendered_frame_height = 100;
+  frame_stats.decoded_frame_width = 200;
+  frame_stats.decoded_frame_height = 100;
 
   comparator.Start(/*max_threads_count=*/1);
   comparator.EnsureStatsForStream(stream, sender, /*peers_count=*/2,
@@ -1378,7 +1383,7 @@
   AssertFirstMetadataHasField(stats.encode_time_ms, "frame_id", "1");
   AssertFirstMetadataHasField(stats.decode_time_ms, "frame_id", "1");
   AssertFirstMetadataHasField(stats.receive_to_render_time_ms, "frame_id", "1");
-  AssertFirstMetadataHasField(stats.resolution_of_rendered_frame, "frame_id",
+  AssertFirstMetadataHasField(stats.resolution_of_decoded_frame, "frame_id",
                               "1");
   AssertFirstMetadataHasField(stats.target_encode_bitrate, "frame_id", "1");
   AssertFirstMetadataHasField(stats.recv_key_frame_size_bytes, "frame_id", "1");
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h
index 93d45e4..6429392 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_internal_shared_objects.h
@@ -63,8 +63,8 @@
   DataSize pre_decoded_image_size = DataSize::Bytes(0);
   uint32_t target_encode_bitrate = 0;
 
-  absl::optional<int> rendered_frame_width = absl::nullopt;
-  absl::optional<int> rendered_frame_height = absl::nullopt;
+  absl::optional<int> decoded_frame_width = absl::nullopt;
+  absl::optional<int> decoded_frame_height = absl::nullopt;
 
   // Can be not set if frame was dropped by encoder.
   absl::optional<StreamCodecInfo> used_encoder = absl::nullopt;
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h
index 69fb1ce..d4152c9 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_shared_objects.h
@@ -142,6 +142,8 @@
   SamplesStatsCounter freeze_time_ms;
   // Mean time between one freeze end and next freeze start.
   SamplesStatsCounter time_between_freezes_ms;
+  SamplesStatsCounter resolution_of_decoded_frame;
+  // Deprecated. Used `resolution_of_decoded_frame` instead.
   SamplesStatsCounter resolution_of_rendered_frame;
   SamplesStatsCounter target_encode_bitrate;
 
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc
index adda17c..bc1e399 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc
@@ -553,10 +553,10 @@
     EXPECT_GE(it->second.encode_time_ms.GetMin(), 20);
     ASSERT_FALSE(it->second.decode_time_ms.IsEmpty());
     EXPECT_GE(it->second.decode_time_ms.GetMin(), 30);
-    ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty());
-    EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(),
+    ASSERT_FALSE(it->second.resolution_of_decoded_frame.IsEmpty());
+    EXPECT_GE(it->second.resolution_of_decoded_frame.GetMin(),
               kFrameWidth * kFrameHeight - 1);
-    EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(),
+    EXPECT_LE(it->second.resolution_of_decoded_frame.GetMax(),
               kFrameWidth * kFrameHeight + 1);
   }
   {
@@ -566,10 +566,10 @@
     EXPECT_GE(it->second.encode_time_ms.GetMin(), 20);
     ASSERT_FALSE(it->second.decode_time_ms.IsEmpty());
     EXPECT_GE(it->second.decode_time_ms.GetMin(), 30);
-    ASSERT_FALSE(it->second.resolution_of_rendered_frame.IsEmpty());
-    EXPECT_GE(it->second.resolution_of_rendered_frame.GetMin(),
+    ASSERT_FALSE(it->second.resolution_of_decoded_frame.IsEmpty());
+    EXPECT_GE(it->second.resolution_of_decoded_frame.GetMin(),
               kFrameWidth * kFrameHeight - 1);
-    EXPECT_LE(it->second.resolution_of_rendered_frame.GetMax(),
+    EXPECT_LE(it->second.resolution_of_decoded_frame.GetMax(),
               kFrameWidth * kFrameHeight + 1);
   }
 }